今天掌握了Bitmap的用法,忍不住再来一次升级版的应用------用键盘控制人物的走动,这个可能在游戏设计中用的很多,不过今儿就先来小试牛刀,呵呵……
本人学习编程有个"癖好" —— 那就是有了想法,下一步就是实现,越快实现越好,不实现就誓不罢休……
好了,F话少说了,还是先来逐步了解需求吧
(1)首先需要一个完整的人物走路分解图,每一个方向4张,分别是:直立、右脚向前、直立、左脚向前
(资源由本人亲自制作,待会儿上传^_^)
(2)加载位图到内存中,这个和Bitmap应用1一样,不再赘述
(3)获取位图ID
首先需要写两个方法:
- IDB_BITMAP GetBitmapID(int dir, int dirCount); //获取当前绘制的位图ID
- void DrawBitmap(HINSTANCE, HDC, int, int, int, int); //绘制位图
- (IDB_BITMAP就是int)
本程序总共需要16张位图,位图ID是从101开始,每一张是紧挨着的(101~116),所以可以通过ID这个特点来控制位图的选择
GetBitmapID()的参数dir取以下4个之1:(位图的排列顺序为: 前后左右)
- //位图的方位
- #define DIR_FRONT 0
- #define DIR_REAR 1
- #define DIR_LEFT 2
- #define DIR_RIGHT 3
参数dirCount取以下4个之1(也就是方向键连续按下的次数,每次对4求余数,因为每一个方向有4张分解图)
- static int frontC, rearC, leftC, rightC;
- //计数是为了控制每个方向所显示状态(立正、右脚向前、立正、左脚向前)
然后简单的运算就能得到相应的位图ID号:
101 + dir*4 + dirCount
(4)用键盘控制人物的走动
由于每一个方向的处理类似,这里就简述一下向前走的控制算法:
- rearC=leftC=rightC=0;//清除
- //控制移动的距离
- if(!(frontC % 2)) //当人物直立时,移动距离控制为10
- {
- y += 10;
- }
- else //当人物左脚或右脚向前时,移动距离控制为2 这是经过多次测试得到的数据,这样控制的效果较好
- {
- y += 2;
- }
- DrawBitmap(hInstance, hdc, DIR_FRONT, frontC, x, y);//绘制人物的状态
- frontC = (frontC+1) % 4;//计算本方向(如果继续按下Dowm键)的下一次移动
(5)清除上一步的状态,也就是将上一步的位图刷掉
方法还是调用BitBlt()方法,只不过是绘制一块白色的位图,仅仅需要将最后一个参数设定为WHITENESS就ok了
好了这就是全过程,以下就是完整代码:
- //前后左右移动的小猫
- #include<windows.h>
- #include<stdio.h>
- #include"resource.h"
- //位图的方位
- #define DIR_FRONT 0
- #define DIR_REAR 1
- #define DIR_LEFT 2
- #define DIR_RIGHT 3
- //类型的重定义
- typedef int IDB_BITMAP;
- /** 为重绘保存上一步的信息 **/
- //保存上一步的位图
- BITMAP lastBitmap;
- //保存上一步位图的坐标
- int lastX, lastY;
- //保存上一步位图的方向和按键计数
- int lastDir, lastDirCount;
- LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
- IDB_BITMAP GetBitmapID(int, int); //获取当前绘制的位图ID
- void DrawBitmap(HINSTANCE, HDC, int, int, int, int); //绘制位图
- int WINAPI WinMain(HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- PSTR szCmdLine,
- int iCmdShow)
- {
- static TCHAR szAppName[] = TEXT("MoveCat");
- HWND hwnd;
- MSG msg;
- WNDCLASS wndclass;
- wndclass.style = CS_HREDRAW | CS_VREDRAW;
- wndclass.lpfnWndProc = WndProc;
- wndclass.cbClsExtra = 0;
- wndclass.cbWndExtra = 0;
- wndclass.hInstance = hInstance;
- wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
- wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
- wndclass.lpszMenuName = NULL;
- wndclass.lpszClassName = szAppName;
- if(!RegisterClass(&wndclass))
- {
- MessageBox(NULL, TEXT("This program requires Windows NT!"),
- szAppName, MB_ICONERROR);
- return 0;
- }
- hwnd = CreateWindow(szAppName,
- TEXT("MoveCat Demo"),
- WS_OVERLAPPEDWINDOW,
- (1366 - 720) / 2,
- (768 - 570) / 2,
- 720,
- 570,
- NULL,
- NULL,
- hInstance,
- NULL);
- ShowWindow(hwnd, iCmdShow);
- UpdateWindow(hwnd);
- while(GetMessage(&msg, NULL, 0, 0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return msg.wParam;
- }
- LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- static HINSTANCE hInstance;//窗口的实例句柄
- static int frontC, rearC, leftC, rightC, x, y;
- //分别表示方位键按键计数和位图显示的位置 计数是为了控制每个方向所显示状态(立正、右脚向前、立正、左脚向前)
- HDC hdc;
- PAINTSTRUCT ps;
- switch(message)
- {
- case WM_CREATE:
- hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
- return 0 ;
- case WM_PAINT:
- hdc = BeginPaint(hwnd, &ps);
- if(lastBitmap.bmWidth)
- {
- DrawBitmap(hInstance, hdc, lastDir, lastDirCount, lastX, lastY);
- }
- else
- {
- DrawBitmap(hInstance, hdc, DIR_FRONT, frontC, x, y);
- frontC = (frontC + 1) % 4;
- }
- EndPaint(hwnd, &ps);
- return 0;
- //用键盘控制位图的显示
- case WM_KEYDOWN:
- hdc = GetDC(hwnd);
- switch(wParam)
- {
- //向前
- case VK_UP:
- frontC=leftC=rightC=0;//清空除当前方向的所有计数
- //控制移动的距离
- if(!(rearC % 2))
- {
- y -= 10;
- }
- else
- {
- y -= 2;
- }
- DrawBitmap(hInstance, hdc, DIR_REAR, rearC, x, y);
- rearC = (rearC+1) % 4;
- break;
- //向后
- case VK_DOWN:
- rearC=leftC=rightC=0;
- //控制移动的距离
- if(!(frontC % 2))
- {
- y += 10;
- }
- else
- {
- y += 2;
- }
- DrawBitmap(hInstance, hdc, DIR_FRONT, frontC, x, y);
- frontC = (frontC+1) % 4;
- break;
- //向左
- case VK_LEFT:
- frontC=rearC=rightC=0;
- //控制移动的距离
- if(!(leftC % 2))
- {
- x -= 15;
- }
- else
- {
- x -= 3;
- }
- DrawBitmap(hInstance, hdc, DIR_LEFT, leftC, x, y);
- leftC = (leftC+1) % 4;
- break;
- //向右
- case VK_RIGHT:
- frontC=rearC=leftC=0;
- //控制移动的距离
- if(!(rightC % 2))
- {
- x += 15;
- }
- else
- {
- x += 3;
- }
- DrawBitmap(hInstance, hdc, DIR_RIGHT, rightC, x, y);
- rightC = (rightC+1) % 4;
- break;
- }
- ReleaseDC(hwnd, hdc);
- return 0;
- case WM_DESTROY:
- PostQuitMessage(0);
- return 0;
- }
- return DefWindowProc(hwnd, message, wParam, lParam);
- }
- IDB_BITMAP GetBitmapID(int dir, int dirCount)
- {
- return 101 + dir*4 + dirCount;
- }
- //绘制位图
- void DrawBitmap(HINSTANCE hInstance, HDC hdc, int dir, int dirCount, int x, int y)
- {
- HBITMAP hBitmap;
- BITMAP bitmap;
- HDC hdcMem;
- //用于创建和hdc兼容的内存设备控制表句柄 也就相当于在内存中绘图,一个缓冲(当然,位图也能支持"截图")
- hdcMem = CreateCompatibleDC(hdc);
- hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(GetBitmapID(dir, dirCount)));
- GetObject(hBitmap, sizeof(BITMAP), &bitmap);
- SelectObject(hdcMem, hBitmap);
- //清除上一步位图信息
- if(lastBitmap.bmWidth)
- {
- BitBlt(hdc, lastX - 1, lastY - 1, lastBitmap.bmWidth + 1, lastBitmap.bmHeight + 1, hdcMem, 0, 0, WHITENESS);
- }
- //保存上一步信息
- lastX = x;
- lastY = y;
- lastDir = dir;
- lastDirCount = dirCount;
- lastBitmap = bitmap;
- //绘制当前位图信息
- BitBlt(hdc, x, y, bitmap.bmWidth - 1, bitmap.bmHeight - 1, hdcMem, 0, 0, SRCCOPY);
- DeleteObject(hBitmap);
- DeleteDC(hdcMem);
- }
运行效果: