一、 计算机角色的简单动画
先是使用Windows本身定时器创建程序的代码:
#include "stdafx.h" #include "MyGameFrame.h" #include <stdio.h> // 全局变量: HINSTANCE hInst; HWND hWnd; HDC hdc, mdc; HBITMAP horse[8]; //图像位图 int num; //当前图像帧数 // 此代码模块中包含的函数的前向声明: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitWindow(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 初始化全局字符串 MyRegisterClass(hInstance); // 执行应用程序初始化: if (!InitWindow(hInstance, nCmdShow))//初始化窗口 { return FALSE;//如果不成功则返回FALSE,并退出程序 } MSG msg; //创建消息类对象 char filename[20] = ""; int i; hdc = GetDC(hWnd); mdc = CreateCompatibleDC(hdc); //加载位图 for (i = 0; i<8; i++) { sprintf_s(filename, "horse%d.bmp", i); horse[i] = (HBITMAP)LoadImage(NULL, filename, IMAGE_BITMAP, 405, 300, LR_LOADFROMFILE); } num = 0; //创建定时器 SetTimer(hWnd, 1, 60, NULL); SelectObject(mdc, horse[num]); BitBlt(hdc, 0, 0, 405, 300, mdc, 0, 0, SRCCOPY); num++; PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);//赋初值 while (msg.message != WM_QUIT) //进入游戏消息循环: { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); //获得游戏玩家输入的消息; DispatchMessage(&msg);//分配玩家消息并响应用户消息。 } } return (int)msg.wParam; } ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex = { wcex.cbSize = sizeof(WNDCLASSEX), CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW, WndProc,0,0, hInstance, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYGAMEFRAME)), LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1),NULL, _T("GameFrame"), LoadIcon(NULL,MAKEINTRESOURCE(IDI_SMALL)) }; return RegisterClassEx(&wcex); } BOOL InitWindow(HINSTANCE hInstance, int nCmdShow) { hInst = hInstance; // 将实例句柄存储在全局变量中 hWnd = CreateWindow ( _T("GameFrame"), _T("游戏框架"), WS_OVERLAPPEDWINDOW^WS_THICKFRAME^WS_MAXIMIZEBOX,//普通样式,不能改变大小,不能最大化 CW_USEDEFAULT, CW_USEDEFAULT, 405, 300, nullptr, nullptr, hInstance, nullptr ); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) //判断消息 { case WM_CREATE: //执行初始化代码 return(0); break; case WM_TIMER: if (num == 8) num = 0; SelectObject(mdc, horse[num]); BitBlt(hdc, 0, 0, 405, 300, mdc, 0, 0, SRCCOPY); num++; break; case WM_DESTROY: DeleteDC(mdc); ReleaseDC(hWnd, hdc); for (int i = 0; i<8; i++) DeleteObject(horse[i]); KillTimer(hWnd, 1); PostQuitMessage(0); break; default: break; } return (DefWindowProc(hwnd, msg, wparam, lparam)); }
动画效果如下
二、接下来是绘制计算机角色的循环动画
使用游戏运行时间产生事件消息的代码:
首先我们需要在全局变量上添加//DWORD全称Double Word,是指注册表的键值,每个word为2个字节的长度,DWORD 双字即为4个字节,每个字节是8位,共32位。 DWORD tNow,tPre; //当前时间与结束时间
删除
//创建定时器 SetTimer(hWnd, 1, 60, NULL);
将消息循环函数更改为
while (msg.message != WM_QUIT) //进入游戏消息循环: { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); //获得游戏玩家输入的消息; DispatchMessage(&msg);//分配玩家消息并响应用户消息。 } else { tNow = GetTickCount(); //取得目前时间 if (tNow - tPre >= 40) { //可在while循环外设置tpre初值 if (num == 8) num = 0; SelectObject(mdc, horse[num]); BitBlt(hdc, 0, 0, 405, 300, mdc, 0, 0, SRCCOPY); tPre = GetTickCount(); //取得结束时间 num++; } } }
删除WndProc()函数中的
Case VM_TIMER相关处理内容
case WM_TIMER: if (num == 8) num = 0; SelectObject(mdc, horse[num]); BitBlt(hdc, 0, 0, 405, 300, mdc, 0, 0, SRCCOPY); num++; break;
以及删除VM_DESTROY中
KillTimer(hWnd, 1);
运行结果同定时器处理结果。
三、接下来是绘制计算机角色的透明动画
#include "stdafx.h" #include "MyGameFrame.h" #include <stdio.h> // 全局变量: HINSTANCE hInst; HWND hWnd; HDC hdc, mdc; HBITMAP bmp; // HBITMAP horse; //图像位图 HBITMAP bg; //背景 int num; //当前图像帧数 //DWORD全称Double Word,是指注册表的键值,每个word为2个字节的长度,DWORD 双字即为4个字节,每个字节是8位,共32位。 DWORD tNow, tPre; //当前时间与结束时间 //为了防止游戏画面更新时出现透明贴图过程中产生的闪烁现象。制作透明动画必须在一个暂存的内存DC上完成每一张走动图的透明然后再贴到窗口上。 HDC bufdc; // 此代码模块中包含的函数的前向声明: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitWindow(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 初始化全局字符串 MyRegisterClass(hInstance); // 执行应用程序初始化: if (!InitWindow(hInstance, nCmdShow))//初始化窗口 { return FALSE;//如果不成功则返回FALSE,并退出程序 } MSG msg; //创建消息类对象 char filename[20] = ""; hdc = GetDC(hWnd); mdc = CreateCompatibleDC(hdc); bufdc = CreateCompatibleDC(hdc);//缓存DC //创建与指定的设备环境相关的设备兼容的位图 bmp = CreateCompatibleBitmap(hdc, 960, 720); SelectObject(mdc, bmp); horse = (HBITMAP)LoadImage(NULL, "horse.bmp", IMAGE_BITMAP, 1624, 300, LR_LOADFROMFILE); bg = (HBITMAP)LoadImage(NULL, "bg.bmp", IMAGE_BITMAP, 960, 720, LR_LOADFROMFILE); int x, y; //绘制图画(一帧) num = 0; //显示图号 x = -50; //贴图起始X坐标 y = 150; //贴图起始Y 坐标 SelectObject(bufdc, bg); BitBlt(mdc, 0, 0, 960, 720, bufdc, 0, 0, SRCCOPY); SelectObject(bufdc, horse); //透明处理 BitBlt(mdc, x, y, 203, 150, bufdc, num * 203, 150, SRCAND); BitBlt(mdc, x, y, 203, 150, bufdc, num * 203, 0, SRCPAINT); BitBlt(hdc, 0, 0, 960, 720, mdc, 0, 0, SRCCOPY); //结束时间 //GetTickCount()函数,该函数的返回值是DWORD型,表示以毫秒为单位的计算机启动后经历的时间间隔 tPre = GetTickCount(); num++; //动画移动 x += 20; if (x >= 900) x = -50; PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);//赋初值 while (msg.message != WM_QUIT) //进入游戏消息循环: { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); //获得游戏玩家输入的消息; DispatchMessage(&msg);//分配玩家消息并响应用户消息。 } else { tNow = GetTickCount();//获取当前时间 if (tNow - tPre >= 100)//程序每隔100个单位时间进行一次绘图操作 { if (num == 8) num = 0; SelectObject(bufdc, bg); BitBlt(mdc, 0, 0, 960, 720, bufdc, 0, 0, SRCCOPY); SelectObject(bufdc, horse); //透明操作 BitBlt(mdc, x, y, 203, 150, bufdc, num * 203, 150, SRCAND); BitBlt(mdc, x, y, 203, 150, bufdc, num * 203, 0, SRCPAINT); BitBlt(hdc, 0, 0, 960, 720, mdc, 0, 0, SRCCOPY); tPre = GetTickCount();//获取结束时间 num++; //动画移动 x += 20; if (x >= 900) x = -50; } } } return (int)msg.wParam; } ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex = { wcex.cbSize = sizeof(WNDCLASSEX), CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW, WndProc,0,0, hInstance, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYGAMEFRAME)), LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1),NULL, _T("GameFrame"), LoadIcon(NULL,MAKEINTRESOURCE(IDI_SMALL)) }; return RegisterClassEx(&wcex); } BOOL InitWindow(HINSTANCE hInstance, int nCmdShow) { hInst = hInstance; // 将实例句柄存储在全局变量中 hWnd = CreateWindow ( _T("GameFrame"), _T("游戏框架"), WS_OVERLAPPEDWINDOW^WS_THICKFRAME^WS_MAXIMIZEBOX,//普通样式,不能改变大小,不能最大化 CW_USEDEFAULT, CW_USEDEFAULT, 960, 720, nullptr, nullptr, hInstance, nullptr ); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) //判断消息 { case WM_CREATE: //执行初始化代码 return(0); break; case WM_DESTROY: DeleteDC(mdc); ReleaseDC(hWnd, hdc); DeleteObject(horse); PostQuitMessage(0); break; default: break; } return (DefWindowProc(hwnd, msg, wparam, lparam)); }
最后结果如下: