这里使用微信中打飞机游戏的素材,先来做一个简单的例子(飞机平滑的移动)——也是我写这个打飞机游戏的第一步
下面通过代码的方式来讲解以下上面所说的几个步骤:
(1)首先获取客户区DC——hdc
hdc = BeginPaint(hwnd, &ps);
(2)获取关于hdc的内存兼容DC——hdcBuffer、获取关于hdc的兼容内存位图cptBmp并选入hdcBuffer中
//用于缓冲的内存DC
hdcBuffer = CreateCompatibleDC(hdc);
//创建内存兼容位图cptBmp
hdc = GetDC(hwnd);
cptBmp = CreateCompatibleBitmap(hdc, sClient.cx, sClient.cy);
ReleaseDC(hwnd, hdc);
//将内存位图选入缓冲内存DC中——以便可以绘制多个位图
SelectObject(hdcBuffer, cptBmp);
(3)一次性贴多个位图 , 那么还应该获取一个关于hdc的内存DC——hdcBmp , 将位图依次选入hdcBmp中,然后将位图从hdcBmp贴到hdcBuffer中
//用于贴位图的内存DC
hdcBmp = CreateCompatibleDC(hdc);
//将背景和飞机都先贴到内存缓冲DC hdcBuffer中(这是在内存中操作的)
for(i=0; i
{
SelectObject(hdcBmp, hBmp[i]);
if(i > 0)
{
//贴飞机(透明贴法,上次讲过)
TransparentBlt(hdcBuffer, sClient.cx * (i-1) / N, y - 128,
sBmp[i].cx, sBmp[i].cy / (SMALL + i-1),
hdcBmp, 0, 0, sBmp[i].cx, sBmp[i].cy / (SMALL + i-1), RGB(255, 255, 255));
}
else
{
//贴背景
BitBlt(hdcBuffer, 0, 0, sBmp[i].cx, sBmp[i].cy,
hdcBmp, 0, 0, SRCCOPY);
}
}
(4)最后将hdcBuffer(也就是内存中)中绘制好的位图贴到原客户区hdc中
//将内存缓冲DC hdcBuffer中所绘制的位图统一贴到客户区DC中(这是在显示屏上操作的)
BitBlt(hdc, 0, 0, sClient.cx, sClient.cy,
hdcBuffer, 0, 0, SRCCOPY);
以下是窗口回调函数的源代码:(内含详尽注释):
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// 背景、飞机位图 内存兼容位图
static HBITMAPhBmp[N], cptBmp;
// 背景、飞机位图大小 客户区大小
static SIZEsBmp[N], sClient;
static inty;//飞机的y坐标
BITMAPbmp;
HINSTANCEhInstance;
HDChdc, hdcBmp, hdcBuffer;
PAINTSTRUCTps;
inti;
switch(message)
{
case WM_CREATE:
//加载背景以及飞机的位图
hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
for(i=0; i
{
hBmp[i] = LoadBitmap(hInstance, MAKEINTRESOURCE(iBmpNames[i]));
GetObject(hBmp[i], sizeof(BITMAP), &bmp);
sBmp[i].cx= bmp.bmWidth;
sBmp[i].cy= bmp.bmHeight;
}
//设置定时器
SetTimer(hwnd, TIMER, 1, NULL);
return 0;
case WM_SIZE:
sClient.cx = LOWORD(lParam);
sClient.cy = HIWORD(lParam);
//创建内存兼容位图cptBmp
hdc = GetDC(hwnd);
cptBmp = CreateCompatibleBitmap(hdc, sClient.cx, sClient.cy);
ReleaseDC(hwnd, hdc);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
//用于贴位图的内存DC
hdcBmp = CreateCompatibleDC(hdc);
//用于缓冲的内存DC
hdcBuffer = CreateCompatibleDC(hdc);
//将内存位图选入缓冲内存DC中——以便可以绘制多个位图
SelectObject(hdcBuffer, cptBmp);
//将背景和飞机都先贴到内存缓冲DC hdcBuffer中(这是在内存中操作的)
for(i=0; i
{
SelectObject(hdcBmp, hBmp[i]);
if(i > 0)
{
//贴飞机(透明贴法,上次讲过)
TransparentBlt(hdcBuffer, sClient.cx * (i-1) / N, y - 128,
sBmp[i].cx, sBmp[i].cy / (SMALL + i-1),
hdcBmp, 0, 0, sBmp[i].cx, sBmp[i].cy / (SMALL + i-1), RGB(255, 255, 255));
}
else
{
//贴背景
BitBlt(hdcBuffer, 0, 0, sBmp[i].cx, sBmp[i].cy,
hdcBmp, 0, 0, SRCCOPY);
}
}
//将内存缓冲DC hdcBuffer中所绘制的位图统一贴到客户区DC中(这是在显示屏上操作的)
BitBlt(hdc, 0, 0, sClient.cx, sClient.cy,
hdcBuffer, 0, 0, SRCCOPY);
//注意回收内存资源
DeleteDC(hdcBmp);
DeleteDC(hdcBuffer);
EndPaint(hwnd, &ps);
return 0;
//用定时器改变飞机的y坐标
case WM_TIMER:
//控制y坐标,使飞机在窗口中不断的移动
y = (y + 1) % (sClient.cy + 128);
InvalidateRect(hwnd, NULL, FALSE);//重绘
return 0;
case WM_DESTROY:
//回收资源
for(i=0; i
DeleteObject(hBmp[i]);
DeleteObject(cptBmp);
//销毁定时器
KillTimer(hwnd, TIMER);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
最后来看看实现的效果: