本系列文章由七十一雾央编写,转载请注明出处。

http://blog.csdn.net/u011371356/article/details/9332377

作者:七十一雾央 新浪微博:http://weibo.com/1689160943/profile?rightmod=1&wvr=5&mod=personinfo

上一节笔记中,我们讲解了键盘响应和鼠标响应,实现了对于玩家的操作,程序做出正确的响应。但是大家在玩游戏的过程中,应该会注意到,在大家没有操作的时候,程序的画面仍然不是静止的,比如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会导致程序失去响应等。


下面贴代码

头文件

// ChildView.h : CChildView 类的接口
//#pragma once// CChildView 窗口class CChildView : public CWnd
{
// 构造
public:CChildView();// 特性
public:CRect m_client;    //保存客户区大小CRect m_heroPos;    //保存英雄的位置CImage m_hero;   //英雄CImage m_bg;      //背景图片
// 操作
public:// 重写protected:virtual BOOL PreCreateWindow(CREATESTRUCT& cs);// 实现
public:virtual ~CChildView();// 生成的消息映射函数
protected:afx_msg void OnPaint();DECLARE_MESSAGE_MAP()
public:afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);afx_msg void OnLButtonDown(UINT nFlags, CPoint point);afx_msg void OnTimer(UINT_PTR nIDEvent);afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
};

CPP文件

// ChildView.cpp : CChildView 类的实现
//#include "stdafx.h"
#include "GameMFC.h"
#include "ChildView.h"#ifdef _DEBUG
#define new DEBUG_NEW
#endif//定时器的名称用宏比较清楚
#define TIMER_PAINT 1
#define TIMER_HEROMOVE 2// CChildViewCChildView::CChildView()
{
}CChildView::~CChildView()
{
}BEGIN_MESSAGE_MAP(CChildView, CWnd)ON_WM_PAINT()ON_WM_KEYDOWN()ON_WM_LBUTTONDOWN()ON_WM_TIMER()ON_WM_CREATE()
END_MESSAGE_MAP()//将png贴图透明
void TransparentPNG(CImage *png)
{for(int i = 0; i <png->GetWidth(); i++){for(int j = 0; j <png->GetHeight(); j++){unsigned char* pucColor = reinterpret_cast<unsigned char *>(png->GetPixelAddress(i , j));pucColor[0] = pucColor[0] * pucColor[3] / 255;pucColor[1] = pucColor[1] * pucColor[3] / 255;pucColor[2] = pucColor[2] * pucColor[3] / 255;}}
}// CChildView 消息处理程序BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
{if (!CWnd::PreCreateWindow(cs))return FALSE;cs.dwExStyle |= WS_EX_CLIENTEDGE;cs.style &= ~WS_BORDER;cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, ::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);//加载背景m_bg.Load("bg.png");//加载英雄图片m_hero.Load("hero.png");TransparentPNG(&m_hero);//设置英雄初始位置m_heroPos.left=100;    //人物左边贴在100的位置m_heroPos.right=100+60; //人物的右边等于左边加上人物的宽度m_heroPos.top=400;m_heroPos.bottom=400+60;return TRUE;
}void CChildView::OnPaint()
{//获取窗口DC指针CDC *cDC=this->GetDC();//获取窗口大小GetClientRect(&m_client);//贴背景m_bg.Draw(*cDC,m_client);//贴英雄m_hero.Draw(*cDC,m_heroPos);//在绘制完图后,使窗口区有效ValidateRect(&m_client);//释放DCReleaseDC(cDC);
}//按键响应函数
void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{//nChar表示按下的键值switch(nChar){case 'd':         //游戏中按下的键当然应该不区分大小写了case 'D':m_heroPos.left+=10;    //向右移动10个像素的单位m_heroPos.right+=10;   //左边和右边都要移动哦break;case 'a':case 'A':m_heroPos.left-=10;m_heroPos.right-=10;break;case 'w':case 'W':m_heroPos.top-=10;m_heroPos.bottom-=10;break;case 's':case 'S':m_heroPos.top+=10;m_heroPos.bottom+=10;break;case 't':case 'T':    //创建定时器SetTimer(TIMER_HEROMOVE,100,NULL);break;case 'i':case 'I':    //撤销定时器KillTimer(TIMER_HEROMOVE);}
}//鼠标左键单击响应函数
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{m_heroPos.left=point.x;m_heroPos.right=m_heroPos.left+60;m_heroPos.top=point.y;m_heroPos.bottom=m_heroPos.top+60;
}//定时器响应函数
void CChildView::OnTimer(UINT_PTR nIDEvent)
{switch(nIDEvent){case TIMER_PAINT:OnPaint();break;  //若是重绘定时器,就执行OnPaint函数case TIMER_HEROMOVE:               //控制人物移动的定时器{m_heroPos.left+=10;m_heroPos.right+=10;}break;}
}int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{if (CWnd::OnCreate(lpCreateStruct) == -1)return -1;// TODO:  在此添加您专用的创建代码//创建一个10毫秒产生一次消息的定时器SetTimer(TIMER_PAINT,10,NULL);return 0;
}

《MFC游戏开发》笔记五到这里就结束了,更多精彩请关注下一篇。如果您觉得文章对您有帮助的话,请留下您的评论,点个赞,能看到你们的留言是我最高兴的事情,因为这让我知道我正在帮助曾和我一样迷茫的少年,你们的支持就是我继续写下去的动力,愿我们一起学习,共同努力,复兴国产游戏。

对于文章的疏漏或错误,欢迎大家的指出。

《MFC游戏开发》笔记五 定时器和简单动画相关推荐

  1. 【 Visual C++】游戏开发笔记之二——最简单的DirectX,vc窗口的编写

    笔记一中我们介绍了如何用代码创建空的win32窗口,然而创建空的win32窗口只完成了一半的工作,接下来要做的工作是设置Direct3D,从而可以在屏幕上渲染图形. Direct3D要调用很多函数才能 ...

  2. 《MFC游戏开发》笔记四 键盘响应和鼠标响应:让人物动起来

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9327377 作者:七十一雾央 新浪微博:http:// ...

  3. 《MFC游戏开发》笔记九 游戏中的碰撞判定初步怪物运动简单AI

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9374935 作者:七十一雾央 新浪微博:http:// ...

  4. 《MFC游戏开发》笔记八 游戏特效的实现(二):粒子系统

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9360993 作者:七十一雾央 新浪微博:http:// ...

  5. 《MFC游戏开发》笔记三 游戏贴图与透明特效的实现

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9313239 作者:七十一雾央 新浪微博:http:// ...

  6. 《MFC游戏开发》笔记十 游戏中的碰撞检测进阶:地图类型障碍物判定

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9394465 作者:七十一雾央 新浪微博:http:// ...

  7. 《MFC游戏开发》笔记七 游戏特效的实现(一):背景滚动

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9344721 作者:七十一雾央 新浪微博:http:// ...

  8. 《MFC游戏开发》笔记六 图像双缓冲技术:实现一个流畅的动画

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9334121 作者:七十一雾央 新浪微博:http:// ...

  9. 《MFC游戏开发》笔记二 建立工程、调整窗口

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9300383 作者:七十一雾央 新浪微博:http:// ...

最新文章

  1. 遍历jenkins build后的文件夹,找出最新“build NO.”复制到制定目录进行操作
  2. Linux下绝对经典的命令
  3. 在C++的类中封装多线程
  4. PhpExcel 删除默认的Sheet
  5. 计算机能不能直接识别汇编语言程序,计算机能直接识别执行用汇编语言编写的程序吗...
  6. 使用awk取passwd10-20行然后重定向
  7. 从云服务器上拷贝文件,从云服务器上拷贝文件
  8. Java 8 Comparator: 列表排序
  9. 贝叶斯算法伪代码_字节跳动算法面经
  10. Oracle 安全性一
  11. pingfang css,前端项目,引入PingFang SC字体
  12. 通达OA二次开发 小飞鱼工作流开发快捷CRM解决方案
  13. 3dmax渲染大图的过程中自动关闭怎么回事?
  14. 服务器安装esxi系统
  15. JSP入门之表格以及常用表单元素(总结自身编程经验以及多本教科书)
  16. mysql localhost值_jdbc:mysql://localhost:3306/mysql这句话中localhost具体指什么的localhost?能修改么?在哪里配置的?...
  17. 日语基础学习 Day 08
  18. 上海域格ASR和高通模块 USB端口分配及Linux下拨号说明
  19. 如何将镜像烧写至iNand(fastboot命令的源码分析)
  20. 【学习笔记】stm32+ESP8266+阿里云+云智能APP

热门文章

  1. java应用程序打包成可jar执行程序
  2. 剑指offer(C++)-JZ36:二叉搜索树与双向链表(数据结构-树)
  3. 从高排到低变成小楼梯儿歌_幼儿数学儿歌,转发收藏!
  4. opencv ubuntu 汉字_ubuntu下没有中文输入法的解决办法
  5. pythonfor循环加2_python – 在For循环中添加List(我最初将List设置为什么?)
  6. java斗地主怎么出牌_斗地主滑动选牌出牌(Cocos Creator)
  7. Gatling性能测试(一)
  8. favicon ico什么意思_你真的知道IPFS与Filecoin是什么吗?
  9. rocketmq mysql_聊聊rocketmq-mysql的BinlogPositionManager
  10. java所参数查询_Java程序查询系统参数