MFC游戏开发笔记五 定时器和简单动画2014-11-03上一节笔记中,我们讲解了键盘响应和鼠标响应,实现了对于玩家的操作,程序做出正确的响应。但是大家在玩游戏的过程中,应该会注意到,在大家没有操作的时候,程序的画面仍然不是静止的,比如NPC会四处走动,怪物仍然会跑过来攻击玩家等,也就是说,画面仍然在随着时间不断的更新。这一点在程序中对应的就是无时无刻不在更新着游戏信息和绘制画面,以便及时的反映出游戏的状态。在WIN 32程序中,一般大家会把绘制程序放到消息循环之中,但是在MFC中由于对WIN 32高度的封装和消息印射机制,我们很难找到消息循环的位置,所以我们就需要采用别的办法。大家现在已经知道,我们绘图都是在OnPaint里进行的,那么我们不断的执行OnPaint函数不就行了吗?实现的方法就是今天要讲解的定时器了。定时器(Timer)对象可以每隔一段时间发出一个时间消息,程序一旦接收到此消息之后,便可以决定接下来要做哪些事情。雾央先说一下定时器大概会有5毫秒左右的误差,精度不够,在实际游戏开发中,很少使用到,但是对于我们初学者来说,这个对于游戏性几乎没有任何影响,还很方便大家的开发,所以我们仍然使用了定时器。下面来介绍如何建立与删除定时器。1.建立定时器Windows API 的SetTimer()函数可为窗口建立一个定时器,并每隔一段时间就发出WM_TIMER消息,此函数的定义是
UINT_PTRSetTimer(UINT_PTRnIDEvent, //定时器代号UINTuElapse, //时间间隔TIMERPROClpTimerFunc //处理函数);
SetTimer()函数的第1个参数是定时器的代号,这个代号在同一个窗口中必须是唯一的,且值不为0,第2个参数则是定时器发出WM_TIMER消息的时间间隔:第3个参则用于设定由系统调用处理WM_TIMER消息的相应函数,如果不用响应函数处理WM_TIMER消息,则此参数应设为NULL。一句话概括,就是SetTimer函数会创建一个ID为第一个参数的定时器,它每隔第二个参数的时间就会执行一次第三个参数指向的函数。如果不需要自己定义处理函数,第三个参数设置为NULL,我们可以使用默认的消息处理函数。下面是设定一个每隔100毫秒发出WM_TIMER消息的定时器的程序代码。SetTimer(1,100,NULL);2.删除定时器定时器建立后,就会一直自动地按照定义设定的时间间隔发出WM_TIMER消息,如果要停用某个定时器,必须使用下面的这个函数:BOOL KillTimer(int 定时器代号); 在MFC中,大家要使用定时器,需要先通过类向导添加“WM_TIMER”消息,添加的具体过程如果有不会的同学请阅读上一节笔记:鼠标响应和键盘响应。在添加完定时器消息后,CChildView.cpp中会出现void CChildView::OnTimer(UINT_PTR nIDEvent) 这个函数,这就是定时器消息处理函数了,它的参数nIDEvent就是表示执行OnTimer函数的定时器的ID了。雾央要强调一下关于创建定时器的位置,大家基本可以在任何地方创建,比如在OnPaint中等,但是千万不要在PreCreateWindow函数中创建定时器,否则大家就会发现程序一运行就会弹出来一个出错框了。如果大家希望在窗口一创建的时候就创建定时器,比如驱动我们窗口绘制的定时器等,那么我们可以添加“WM_CREATE”消息,在这里面进行创建。在示例程序中我们要实现的是按下T键人物自动向右移动,按下I键定值移动。大家如果自己运行一下程序,就会感觉这有几分动画的影子了。事实上,如果让人物移动的时候,变化一下图片,比如几张跑动的图片不断的切换,那么就是一个真正意义上的动画了。另外,雾央有一个感到非常抱歉的事情要和大家说明一下,在之前的代码中,雾央漏掉了一句很重要的代码,在OnPaint函数中释放DC即ReleaseDC之前要加上ValidateRect(&m_client);这个函数的作用是使绘图区变得有效。在windows中,如果我们的窗口被遮挡了什么的,窗口那部分就变得无效,就会产生WM_PAINT消息,当绘制完毕后,必须要使窗口变得有效,否则系统将周而复始的产生WM_PAINT消息,使得CPU占用率非常高,而且还会出现很多莫名其妙的问题,比如使用MessageBox会导致程序失去响应等。