VC++游戏编程----基础动画显示1
来源:互联网 发布:模拟定位软件 编辑:程序博客网 时间:2024/05/16 09:31
一、定时器
Timer定时器对象可以再每隔一段时间发出一个时间消息,程序收到消息后,就可以执行一些操作。比如,可以设置定时器来播放静态的连续图片,就可以产生动画效果。这也是通常显示动画的一种方式。
Windows API中有这样的函数:SetTimer()为我们定义一个定时器。函数原型:
UINT_PTR SetTimer( HWND hWnd, // 窗口句柄 UINT_PTR nIDEvent, // 定时器代号 UINT uElapse, // 时间设定的值,单位为毫秒 TIMERPROC lpTimerFunc // 定时器响应函数);
这里举一个小例子:
SetTimer(hwnd, // 窗口句柄 IDT_TIMER1, // 代号 10000, // 10秒 (TIMERPROC) NULL); // 没有响应函数 SetTimer(hwnd, IDT_TIMER2, 5000, (TIMERPROC) NULL); case WM_TIMER: switch (wParam) { case IDT_TIMER1: // 执行10秒的操作 return 0; case IDT_TIMER2: // 执行5秒的操作 return 0; }
创建后自然需要删除定时器。KillTimer()就是用来终止某个定时器的
BOOL KillTimer( HWND hWnd, // 窗口句柄 UINT_PTR uIDEvent // 定时器代号);
运用定时器使预先做好的连续的静态图片播放,形成动画的效果。
新建Win32程序,在VS2008中默认使用默认的生成窗口的代码。
这里顺便提一提,在VS中使用多字节字符集设置可以在解决方案资源管理器中右击方案,选择属性,打开的属性页里可以设置。
如图:
接下来,在程序头部添加全局变量:
HBITMAP girl[7]; // 用于7张人物的位图数组HDC mdc,hmdc;int num; // 用于计数循环
在InitInstance()函数中添加代码:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){HWND hWnd;char filename[20] = "";int i; hInst = hInstance; // 将实例句柄存储在全局变量中hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);if (!hWnd){ return FALSE;}MoveWindow(hWnd, 10, 10, 600, 450, true);ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);hmdc = GetDC(hWnd);mdc = CreateCompatibleDC(hmdc);//将7张位图载入for (i = 0; i < 7; i++){ sprintf(filename, "girl%d.bmp", i);girl[i] = (HBITMAP)LoadImage(NULL,filename,IMAGE_BITMAP,640,480,LR_LOADFROMFILE);}num = 0;SetTimer(hWnd, 1, 500, NULL); // 设定0.5秒的定时器MyPaint(hmdc);return TRUE;}
WndProc()中添加WM_TIMER消息:
case WM_TIMER:MyPaint(hmdc);break;
程序退出是需要析构所有创建的对象:
case WM_DESTROY://删除和释放工作DeleteDC(mdc);ReleaseDC(hWnd, hmdc);for (i = 0; i < 7; i++){DeleteObject(girl[i]);}KillTimer(hWnd, 1);PostQuitMessage(0);break;
MyPaint()函数的实现如下:
void MyPaint(HDC hdc){if(num == 7)num = 0;SelectObject(mdc,girl[num]);BitBlt(hdc,0,0,600,450,mdc,0,0,SRCCOPY);num++;}
这样,程序就算完成了。运行,会看到小女孩在摆动的动画。
我们可以加快定时器的速率,使动画看起来更加连贯。
这里是源代码文件:点击
二、游戏循环
在上例中,通过Timer来设定动画的帧来显示游戏,这事实上市仅仅使用在小型游戏中的方式。一般来说,我们为了是游戏显示得更加顺畅,每秒钟必须更新画面25次以上。在此之中,我们还需要处理其他大量的游戏操作。而用定时器来驱动,往往得不到我们想要的画面效果。这里提出了一种叫做“游戏循环”的概念。
游戏循环是将原先程序中的消息循环加以修改,方法是判断其中的内容目前是否要处理的消息,如果有则进行,否则按照设定的时间间隔来重绘画面。
这里借助一个例子讲解:
在WinMain函数中
//游戏循环while (msg.message != WM_QUIT){if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);}else{tNow = GetTickCount(); // 获得系统开启时间if (tNow - tPre >= 100)MyPaint(hdc); // 绘图函数}}
msg.message收到不是WM_QUIT消息时,进行运行循环。PeekMessage检测是否有处理消息(包括WM_QUIT)。没有消息就返回0,否则返回非0。值得注意的是,不能用GetMessage()取代PeekMessage()。
此例子和上面的例子是同样的原理,显示一个动画。
运行后,显示的也是一个动画。本动画由七副静态图循环粘贴形成。即,BITMAP man[7]
整个程序如下:
#include <windows.h>#include <stdio.h>// 全局变量HINSTANCE hInst;HBITMAP man[7];HDC hdc,mdc;HWND hWnd;// 分别记录上次绘图时间,本次准备绘图时间,记录每秒开始的时间DWORD tPre, tNow, tCheck;int num, frame, fps;// 函数声明ATOM MyRegisterClass(HINSTANCE hInstance);BOOL InitInstance(HINSTANCE, int);LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);void MyPaint(HDC hdc);// 入口函数int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){MSG msg;ZeroMemory(&msg, sizeof(MSG));MyRegisterClass(hInstance);if( !InitInstance(hInstance, nCmdShow) ){return FALSE;}//游戏循环while (msg.message != WM_QUIT){if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);}else{tNow = GetTickCount(); // 获得系统开启时间if (tNow - tPre >= 100)MyPaint(hdc); // 绘图函数}}return msg.wParam;}//注册窗口类函数ATOM MyRegisterClass(HINSTANCE hInstance){WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX); wcex.style= CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc= (WNDPROC)WndProc;wcex.cbClsExtra= 0;wcex.cbWndExtra= 0;wcex.hInstance= hInstance;wcex.hIcon= NULL;wcex.hCursor= NULL;wcex.hCursor= LoadCursor(NULL, IDC_ARROW);wcex.hbrBackground= (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName= NULL;wcex.lpszClassName= "canvas";wcex.hIconSm= NULL;return RegisterClassEx(&wcex);}// 初始化窗口BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){char filename[20] = "";int i;hInst = hInstance;hWnd = CreateWindow("canvas", "游戏循环" , WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);if (!hWnd){return FALSE;}MoveWindow(hWnd,10,10,600,450,true);ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);hdc = GetDC(hWnd);mdc = CreateCompatibleDC(hdc);// 循环载入各个静态图for(i=0;i<7;i++){sprintf(filename,"man%d.bmp",i);man[i] = (HBITMAP)LoadImage(NULL,filename,IMAGE_BITMAP,640,480,LR_LOADFROMFILE);}num = 0;frame = 0;MyPaint(hdc);return TRUE;}// 绘制图形void MyPaint(HDC hdc){char str[40] = "";if(num == 7)num = 0;frame++; // 更新画面次数加1if(tNow - tCheck >= 1000){fps = frame;frame = 0;tCheck = tNow;}SelectObject(mdc,man[num]);sprintf(str,"每秒钟显示 %d 个画面",fps);TextOut(mdc,0,0,str,strlen(str));BitBlt(hdc,0,0,600,450,mdc,0,0,SRCCOPY);tPre = GetTickCount(); // 记录此次绘图时间num++;}// 消息循环LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){int i;switch (message){case WM_DESTROY: // 清理回收DeleteDC(mdc);for(i=0;i<7;i++)DeleteObject(man[i]);ReleaseDC(hWnd,hdc);PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;}
相信有了第一部分的例子,对于这部分的例子理解并不难。
- VC++游戏编程----基础动画显示1
- VC++游戏编程基础(书)<1>
- 游戏编程基础(三)GDI游戏动画基础
- DirectDraw 游戏编程基础(1)
- iOS动画编程-View动画[ 1 ] 基础View动画
- 【Visual C++】游戏开发笔记之十 基础动画显示(三) 透明动画的实现
- 【Visual C++】游戏开发笔记之十 基础动画显示(三) 透明动画的实现
- 【Visual C++】游戏开发笔记之十 基础动画显示(三) 透明动画的实现
- 游戏开发笔记之十 基础动画显示(三) 透明动画的实现
- 【Visual C++】游戏开发笔记之十 基础动画显示(三) 透明动画的实现
- 【Visual C++】游戏开发笔记之十 基础动画显示(三) 透明动画的实现
- VC++游戏编程
- 游戏开发笔记之八——基础动画显示(二)游戏循环的使用
- 游戏编程基础(五)背景地图滚动显示
- 基础动画显示
- VC++游戏编程----游戏画面特效制作1
- 【读书笔记《Android游戏编程之从零开始》】16.游戏开发基础(动画)
- 游戏中动画的基础
- DecimalFormat类的学习
- 面向对象编程进阶
- POJ3268:Silver Cow Party
- linux c语言编程中《进程的管理wait函数》
- java心得---继承
- VC++游戏编程----基础动画显示1
- 连接两个字符串
- SD卡接口的完整规范
- 使用 Socket 通信实现 FTP 客户端程序
- POJ-2488 A Knight's Journey 解题报告(搜索) 马跳遍棋格的字典序问题
- 五大常用算法之五:分支限界法
- 多线程设计模式
- 数据库导出到xml中
- 输入一个带符号的十进制数字串,以四位十六进制的形式输出该串对应的值