我现在做的一个小游戏的刷新速度很慢。请问如何提高效率1.我的程序是基于win32的。
2.绘图采用gdi双缓冲的方式,
3.OnPaint里用了贴图的方式贴出部分代码void PicDlg::RandDrawPicture(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WCHAR strFileName[128];
swprintf(strFileName, _T("%sPicture\\pic%d.bmp"), g_strAppPath, m_nRandIndex); HBITMAP hBitmap = (HBITMAP)LoadImage(g_hInstance, strFileName, IMAGE_BITMAP,
0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION); BITMAP object;
GetObject(hBitmap, sizeof(BITMAP), &object);
int nPicWidth = object.bmWidth;
int nPicHeitht = object.bmHeight; HDC hBackDC = NULL;
hBackDC = CreateCompatibleDC(NULL);
SelectObject(hBackDC, m_hBitmap);
DeleteObject(hBitmap); RECT rect;
GetClientRect(hWnd, &rect);
StretchBlt(m_hMemDC, // 拷贝到内存DC中
0, 0,
rect.right - rect.left, rect.bottom - rect.top,
hBackDC,
0, 0,
nPicWidth, nPicHeitht,
SRCCOPY);
}void PicDlg::OnPaint(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT paint;
HDC hDC = ::BeginPaint(hWndDlg, &paint); RECT rcClient;
::GetClientRect(hWndDlg, &rcClient); RandDrawPicture(hWndDlg, uMsg, wParam, lParam);
::BitBlt(hDC,
0, 0,
rcClient.right, rcClient.bottom,
m_hMemDC,
0, 0,
SRCCOPY);
::EndPaint(hWndDlg, &paint);
}////////////////////////////////////////////////////////////////////
这是其中一个对话框的刷新
有很多这样的对话框拼出整个界面。现在修改一下数据,我就刷新下界面,要等个几百毫秒,界面才刷新过来,有点迟钝。请问怎么优化,速度慢在哪了?(配置高的机器还好,差一点的就特别慢)谢谢了!!!!
2.绘图采用gdi双缓冲的方式,
3.OnPaint里用了贴图的方式贴出部分代码void PicDlg::RandDrawPicture(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WCHAR strFileName[128];
swprintf(strFileName, _T("%sPicture\\pic%d.bmp"), g_strAppPath, m_nRandIndex); HBITMAP hBitmap = (HBITMAP)LoadImage(g_hInstance, strFileName, IMAGE_BITMAP,
0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION); BITMAP object;
GetObject(hBitmap, sizeof(BITMAP), &object);
int nPicWidth = object.bmWidth;
int nPicHeitht = object.bmHeight; HDC hBackDC = NULL;
hBackDC = CreateCompatibleDC(NULL);
SelectObject(hBackDC, m_hBitmap);
DeleteObject(hBitmap); RECT rect;
GetClientRect(hWnd, &rect);
StretchBlt(m_hMemDC, // 拷贝到内存DC中
0, 0,
rect.right - rect.left, rect.bottom - rect.top,
hBackDC,
0, 0,
nPicWidth, nPicHeitht,
SRCCOPY);
}void PicDlg::OnPaint(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT paint;
HDC hDC = ::BeginPaint(hWndDlg, &paint); RECT rcClient;
::GetClientRect(hWndDlg, &rcClient); RandDrawPicture(hWndDlg, uMsg, wParam, lParam);
::BitBlt(hDC,
0, 0,
rcClient.right, rcClient.bottom,
m_hMemDC,
0, 0,
SRCCOPY);
::EndPaint(hWndDlg, &paint);
}////////////////////////////////////////////////////////////////////
这是其中一个对话框的刷新
有很多这样的对话框拼出整个界面。现在修改一下数据,我就刷新下界面,要等个几百毫秒,界面才刷新过来,有点迟钝。请问怎么优化,速度慢在哪了?(配置高的机器还好,差一点的就特别慢)谢谢了!!!!
使用DC进行绘制是不可能很高效的吧,我觉得你需要学习DirectX或者OpenGL
我做了个动画效果,移动对话框,其实我是想做个图片移动的效果,就把图片贴在窗口上。移动窗口,到达效果。但是每20毫秒刷新显示下,但是看到的是白色的窗口移动,没有图片出来。配置高的机器可以看到效果,我是在Arm9的机器运行的,我的代码有效率的问题吗?void PicDlg::MoveUpThread(LPVOID pPrarm)
{
PicDlg *This = (PicDlg *)pPrarm;
int nHeight = This->m_rectCur.bottom - This->m_rectCur.top;
for (int i = 0; i < nHeight; i += 3)
{
This->m_rectCur.top -= 3;
This->m_rectCur.bottom -= 3;
MoveWindow(g_hPicWnd,
This->m_rectCur.left, This->m_rectCur.top,
This->m_rectCur.right - This->m_rectCur.left,
This->m_rectCur.bottom - This->m_rectCur.top,
true);
Sleep(50);
}}
2、你在进行画图时,用了一次hbackDC画到内存memdc上,又从memdc拷贝到实际的窗口dc,这样做没必要,只要先把图片画到memdc上就好了,处理好画图的顺序,比如在底层的先画,再画上面的。
3、做精灵动画不能采用移动窗口的方式,而应该是快速擦除重画。这样效率是最高的,移动窗口,要经过MFC的消息循环,不能保证实时性,特别是WM_PAINT消息是非同步消息,系统有时间才会去处理的,不是实时处理的。
{
DWORD dwTick = GetTickCount() + Delay_ms;
while(GetTickCount() < dwTick)
{
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Sleep(0);
}
}本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zgl7903/archive/2010/03/15/5382869.aspx
比如:在屏幕画一个移动的圆,你所要做的就是1、擦除上次的圆。2、画新位置的圆。如果窗口收到了WM_PAINT之类的消息,你也是擦掉当前的圆,再画一个圆,相当于画了两次圆(你也可以新旧位置判断,只画一次),但还是可以看到圆啊。擦是擦掉旧的,重画是画新的。。
{
PAINTSTRUCT paint;
HDC hDC = ::BeginPaint(hWndDlg, &paint); RECT rcClient;
::GetClientRect(hWndDlg, &rcClient);
//RandDrawPicture(hWndDlg, uMsg, wParam, lParam); HDC hBackDC = NULL;
hBackDC = CreateCompatibleDC(NULL);
SelectObject(hBackDC, m_hBitmap);
::BitBlt(hDC,
0, 0,
rcClient.right, rcClient.bottom,
hBackDC,
0, 0,
SRCCOPY);
DeleteDC(hBackDC);
::EndPaint(hWndDlg, &paint);
}跳到OnPaint里面后m_hBitmap突然又为0了(之前已经加载好的),怎么搞的?
这个是一个原则。你的LoadImage是放在哪儿的?怎么写的。
{
int x = GetLastError();
srand((unsigned)GetRandSeed());
m_nRandIndex = rand() % PIC_COUNT + 1; // 加载位图
WCHAR strFileName[128];
swprintf(strFileName, _T("%sPicture\\pic%d.bmp"), g_strAppPath, m_nRandIndex);
#ifdef _WINXP
HBITMAP m_hBitmap = (HBITMAP)LoadImage(g_hInstance, _T("C:\\1.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
#else
HBITMAP m_hBitmap = (HBITMAP)SHLoadDIBitmap(strFileName);
#endif
x = GetLastError(); BITMAP object;
GetObject(m_hBitmap, sizeof(BITMAP), &object);
m_nPicWidth = object.bmWidth;
m_nPicHeitht = object.bmHeight;
}
这个函数在OnPaint之前调用的
m_hBitmap已经有值了,GetLastError也等于 0
为什么跳到OnPaint里就没了呢?
{
PAINTSTRUCT paint;
HDC hDC = ::BeginPaint(hWndDlg, &paint); RECT rcClient;
::GetClientRect(hWndDlg, &rcClient); HDC hBackDC = NULL;
hBackDC = CreateCompatibleDC(NULL);
SelectObject(hBackDC, m_hBitmap); ::BitBlt(hDC,
0, 0,
rcClient.right, rcClient.bottom,
hBackDC,
0, 0,
SRCCOPY);
DeleteDC(hBackDC);
::EndPaint(hWndDlg, &paint);
}void PicDlg::MoveDown(void)
{
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MoveDownThread, this, 0, NULL);
}void PicDlg::MoveDownThread(LPVOID pPrarm)
{
PicDlg *This = (PicDlg *)pPrarm; g_GameManage.GetBigVideoRect(This->m_rectCur);
int nHeight = This->m_rectCur.bottom - This->m_rectCur.top;
This->m_rectCur.bottom = 0;
This->m_rectCur.top = This->m_rectCur.bottom - PIC_HEIGHT; MoveWindow(g_hPicWnd,
This->m_rectCur.left, This->m_rectCur.top,
This->m_rectCur.right - This->m_rectCur.left,
This->m_rectCur.bottom - This->m_rectCur.top,
false);
for (int i = 0; i < PIC_HEIGHT; i += 5)
{
This->m_rectCur.top += 5;
This->m_rectCur.bottom += 5;
MoveWindow(g_hPicWnd,
This->m_rectCur.left, This->m_rectCur.top,
This->m_rectCur.right - This->m_rectCur.left,
This->m_rectCur.bottom - This->m_rectCur.top,
false);
InvalidateRect(g_hPicWnd, NULL, false);
_Sleep_(20);
}
}INT_PTR PicDlg::DlgProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_PAINT:
{
OnPaint(hWndDlg, uMsg, wParam, lParam);
}
break;
case WM_ERASEBKGND:
return 0;
break;
} return 0;
}
怎么解决闪烁的问题
查查这个东西的用法。
还是闪得厉害
请教下,不用对话框,我应该在哪个窗口绘制呢?
我现在的贴图的窗口的下面还有一个窗口的。是播放视频的。应该不能在那上面绘吧。
return 1;仔细看MSDN:
An application should return nonzero in response to WM_ERASEBKGND if it processes the message and erases the background; this indicates that no further erasing is required. If the application returns zero, the window will remain ed for erasing. (Typically, this indicates that the fErase member of the PAINTSTRUCT structure will be TRUE.)
return 1;
仍然闪我在WM_ERASEBKGND里把onpaint中的内容再绘一遍就不闪了。
能解释下吗?
但你如果在WM_ERASEBKGND中画了背景,视频播放不引起背景变化,所以感觉不到闪烁,但还是建议你不要这样来实现精灵动画,呵呵。。感觉很别扭。
// 绘制背景
void GameView::DrawBackgroud(void)
{
// 绘制到内存DC上
::BitBlt(g_hMemDC,
0, 0,
SCREEN_WIDTH, SCREEN_HEIGHT,
m_hBkgrdDC,
0, 0,
SRCCOPY);
}
这样还能怎么优化啊
// 绘制背景
void GameView::DrawBackgroud(void)
{
///空
}
这样就快多了。
应该怎么处理呢?
每次bitblt的范围小点行吗?
只bitblt需要改变背景的区域,其它背景都没变的。但是又不知道怎么取改变了背景的区域,
PAINTSTRUCT里就有要刷新的矩形,仔细看MSDN,很重要的。要做的深入一点不仔细看文档是不行的。
请问如何得到这个结构呢,我看了下MSDN,好像没提到。
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32];
} PAINTSTRUCT;
RECT rcPaint;
你真的看了吗?
rcPaint,Specifies the upper-left and lower-right corners of the rectangle in which the painting is requested. rcPaint,指定需要绘制矩形区域的左上和右下角的坐标。这是设置需要绘制的区域吧,我想问的是,怎么取得哪写区域发生的变化,需要重绘,返回的应该是多个区域的链表类似的结构才对吧,我的理解哈。
如果要精确的无效区域,用GetUpdateRgn,得到的是个区域。
不过用区域的效率大部分时间里不如直接用RECT。
而且我看你onpaint函数里面好像对整个DC重绘了,其实有时候不用全部重绘,只需要重绘修相应修改的区域就行。