不使用定时器,在MFC中如何实现游戏android 循环定时器?

MFC中定时器的使用
巧妙地使用定时器能达到意想不到的效果,写界面的时候能实现渐变,也能帮助多线程控制等
我们知道,在VC的MFC中,已经为我们封装好了很多全面和强大的函数集,所以在MFC编程时,巧妙地调用MFC函数库可以为我们省去很多麻烦。其中定时器也可以在MFC程序中很好地利用。
在MFC中和定时器相关的有三个函数:
1.设置定时器(定义一个定时器的属性):
SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK
EXPORT*lpfnTimer)(HWND,UINT,UINT,DWORD));
2.定时器响应(响应系统定义WM_TIMER消息):
OnTimer( UINT nIDEvent );
3.释放定时器:
KillTimer( int nIDEvent );
UINT nIDEvent:定时器的ID,在一个程序中用这个ID来确定是那个定时器发送的消息。
UINT nElapse: 定义刷新时间,即间隔多长时间刷新一次,单位是毫秒。
void (CALLBACK EXPORT* lpfnTimer)( HWND, UINT, UINT,
DWORD):回调函数的参数,实现刷新时所做的操作,一般情况下都设为0。
在这里就用一个简单的例子来说明定时器在MFC中是如何使用的。
1.建立单文档程序Timer。
2.在resource.h中定义两个定时器的ID
#define TIMER1 1
#define TIMER2 2
3.在CMainFrame的OnCreate函数中定义两个定时器的属性。
SetTimer(TIMER1,3000,0);
SetTimer(TIMER2,5000,0);
4.在类视图中右击CMainFrame属性,在消息响应函数中找到WM_TIMER,然后添加响应函数OnTimer()。
void CMainFrame::OnTimer(UINT nIDEvent)
// TODO: Add your message handler code here and/or call
&& switch(nIDEvent)
case TIMER1:
&&&&&&&&&&&&
AfxMessageBox("定时器1!");
&&&&&&&&&&&&
case TIMER2:
&&&&&&&&&&&
AfxMessageBox("定时器2!");
&&&&&&&&&&&
CFrameWnd::OnTimer(nIDEvent);
5.在CMainFrame的析构函数中添加释放定时器函数。
&&&&&&&&&&&&&
KillTimer(TIMER1);
&&&&&&&&&&&&&&&&
KillTimer(TIMER2);
这样,一个简单的定时器程序就生成了,运行后可以看到,每隔3秒就会弹出一个消息对话框“定时器1”,每隔5秒就会弹出一个消息对话框“定时器2”。
这种情况是在程序运行后定时器就直接启动了,很多时候我们需要的是在响应一次事件或者说点击一个按钮后再去执行定时器,那么这时应该怎么修改呢?也用一个实例来说明吧,因为我觉得可能说一大堆废话也抵不上一个简单而正确的实例更具说服力。
另一个人做的
现在,我生成了一个MFC多文档应用程序,我希望在点击菜单条上的某个按钮后再去执行定时器。这时就不是在CMainFrame里面操作了,因为我们是要在对话框上进行定时器的操作,而CView这个类是负责对话框的对应操作,所以要把定时器定义在CView里面。
1.建立多文档程序Timer。
2.在resource.h中定义两个定时器的ID
#define TIMER1 1
#define TIMER2 2
3.在CTimerView的OnInitialUpdate函数中定义两个定时器的属性。
SetTimer(TIMER1,3000,0);
SetTimer(TIMER2,5000,0);
4.在类视图中右击CTimerView属性,在消息响应函数中找到WM_TIMER,然后添加响应函数OnTimer()。
void CTimerView::OnTimer(UINT nIDEvent)
// TODO: Add your message handler code here and/or call
//Hwnd为一个变量,初始值为false,点击某个按钮后在其响应函数中将其置为true
switch(nIDEvent && Hwnd){
case TIMER1:
AfxMessageBox("定时器1!");
case TIMER2:
AfxMessageBox("定时器2!");
CFrameWnd::OnTimer(nIDEvent);
5.在CTimerView中添加OnDestroy()函数,在函数中释放定时器。
KillTimer(TIMER1);
KillTimer(TIMER2);
现在,运行程序后,没有马上弹出预定的对话框,而是在我们点击某个按钮或者响应某个事件后对话框才弹出,同样是点击按钮后,每隔3秒弹出对话框“定时器1”,每隔5秒弹出“定时器2”。
其实在不同的类,定时器的用法都是基本一致的,只要找到类的初始函数和释放函数,就能轻松实现定时功能了,就这么简单。
基于对话框的定时器程序
1.打开VC,新建一基于对话框的工程,工程名为Test在对话框上添加一按钮,将其ID改为IDC_BUTTON_START,Caption改为Start. 映像该按钮的BN_CLICKED消息,void
CTestDlg::OnButtonStart();
2.再在对话框上添加一按钮,ID为ID_BUTTON_STOP,Caption改为Stop,映像消息为void
CTestDlg::OnButtonStop();
3.添加一个Lable,ID改为IDC_STATIC_TIME,用于记数,表明定时器函数的执行。
4.映像对话框的WM_TIMER消息,void CTestDlg::OnTimer(UINT nIDEvent);
以上的实现函数如下所示:
void CTestDlg::OnButtonStart()
SetTimer(1,1000,NULL);//启动定时器1,定时时间是1秒
void CTestDlg::OnButtonStop()
KillTimer(1);&&&&&&&
//关闭定时器1。
void CTestDlg::OnTimer(UINT nIDEvent)
static int nTimer=0;
CString strTmp="";
strTmp.Format("Timer:&&&
%d",nTimer++);
CWnd *pWnd=GetDlgItem(IDC_STATIC_TIME);
pWnd-&SetWindowText(strTmp);
//在Lable中设置新值,表明定时器已经工作。
CDialog::OnTimer(nIDEvent);
回调函数的使用。
如果不想使用窗体的WM_TIMER消息函数处理,可以使用回调函数来取代,读者可以在上面例子的基础上,增加一个回调函数,以证实前面的讨论。
首先,定义一个回调函数,回调函数的定义必须按照如下格式。
void CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD
我的实现函数如下:
void CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD
AfxMessageBox("Timer is running!");//定时器时间到,强出一对话框,表明定时器已经运行。
将上面的启动函数稍做修改
void CTestDlg::OnButtonStart()
SetTimer(1,1000,NULL);//启动定时器1,定时时间是1秒
SetTimer(1,1000,(TIMERPROC)TimerProc);//用回调函数处理,此时对话框的消息处理函数不再处理。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。& & &保卫萝卜~想法一直存在于想法,实战才是硬道理!有想法就去实现,眼高手低都是空谈。
一、游戏主循环GameSchedule
& & &主循环是游戏处理逻辑,控制游戏进度的地方,处理好主循环是很重要的。写一个简单的游戏主循环是很有必要的~
游戏主循环有开始、有结束、有暂停、有恢复把握好进度,控制好游戏,处理好逻辑。我在Cocos2dx进入主场景时开启游戏主循环,在永远不再使用时删除主循环,在游戏暂停时pause主循环,在游戏恢复时resume主循环。
#ifndef __GameSchedule__
#define __GameSchedule__
#include "cocos2d.h"
USING_NS_CC;
class GameSchedule : public Ref
static GameSchedule* getInstance();
void start();
void end();
static void pause();
static void resume();
virtual void onExit();
~GameSchedule();
void globalUpdate(float time);
void init();
#include "GameSchedule.h"
#include "GameDelayTime.h"
#include "SceneMgr.h"
static GameSchedule* _instance =
static bool _pause = true;
GameSchedule* GameSchedule::getInstance()
if( !_instance )
_instance = new GameSchedule();
_instance-&init();
void GameSchedule::init()
_pause = true;
void GameSchedule::start()
log("GameSchedule -----& start ");
_pause = false;
Director::getInstance()-&getScheduler()-&schedule(schedule_selector(GameSchedule::globalUpdate),this,0,false);
void GameSchedule::end()
log("GameSchedule -----& end ");
Director::getInstance()-&getScheduler()-&unschedule(schedule_selector(GameSchedule::globalUpdate),this);
CC_SAFE_DELETE(_instance);
void GameSchedule::pause()
log("GameSchedule -----& pause ");
_pause = true;
void GameSchedule::resume()
log("GameSchedule -----& resume ");
_pause = false;
void GameSchedule::globalUpdate(float time)
if( _pause ) return;
GameDelayTime::getInstance()-&UpdateTime(time);
SceneMgr::getInstance()-&UpdateScene(time);
void GameSchedule::onExit()
log("GameSchedule dispose!!!!1111");
GameSchedule::~GameSchedule()
log("GameSchedule dispose!!!!222");
GameSchedule.cpp
使用静态单例创建主循环对象,并使用Schedule 注册函数接口,作为引擎的主循环回调。
Director::getInstance()-&getScheduler()-&schedule(schedule_selector(GameSchedule::globalUpdate),this,0,false);
这里的GameSchedule::globalUpdate函数将是逻辑处理的开始,定时器刷新,场景处理等。
在进入主场景时开启入主循环,实现游戏的逻辑处理。
二、定时器GameDelayTime
& & &定时器也就是定时回调,在有限时间内调用指定目标函数。这在一些游戏逻辑处理中很有用,包括一些动作处理(Cocos2dx中有延时动作和回调动作)。当然,有一个自己写的处理函数,我想是非常棒的~自己动手才能理解。
& & &定时器的处理类GameDelayTime将会集中处理所有的定时器、更新定时器、删除定时器。当然GameDelayTime类将会出现在游戏主循环GameSchedule::globalUpdate函数中,使用游戏主循环控制整个游戏的所有动作表现,当游戏暂停时停止所有逻辑处理,等待再次恢复。定时器数据类DelayTimeDate是定时器的数据中心,记录定时器的延迟时间、延迟目标等。如果达到延迟时间将会调用目标函数,并退出自更新,等待处理类GameDelayTime删除。
& & &游戏中的定时器是危险的,如果在场景中使用了定时器或在结点对象中使用定时器时,必须在退出场景或移除结点时删除所使用的定时器!
如:Node::onExit()时 删除定时器对象。这是至关重要的!如果结点已移除而没有删除定时器对象,那么定时器指针会一直存在于内存,指针成为野指针,到达延迟时间时被调用将会产生不可预料的麻烦。(我很想知道该怎样去判断一个函数指针指向的目标是否被释放&&这样就可以避免野指针调用后崩溃,自己c++太菜&&希望有人能告诉我)。
#ifndef __GameDelayTime__
#define __GameDelayTime__
#include "cocos2d.h"
using namespace
USING_NS_CC;
class DelayTimeDate
static DelayTimeDate* create( float delayTime,std::function&void()& callback );
CC_SYNTHESIZE( float, delayTime, DelayTime );
CC_SYNTHESIZE( std::function&void()&, callback, Callback );
CC_SYNTHESIZE_READONLY( float, time, TotalTime );
bool update(float time);
void init( float delayTime,std::function&void()& callback ){
_time = 0;
setDelayTime(delayTime);
setCallback(callback);
class GameDelayTime
static GameDelayTime* getInstance();
DelayTimeDate* addDelayTimeCallBack( float delayTime,std::function&void()& callback );
void removeDelayTimeCallBack( DelayTimeDate* delayTimeDate );
void UpdateTime(float time);
vector&DelayTimeDate*& _keyM
void init();
#include "GameDelayTime.h"
static GameDelayTime* _instance =
GameDelayTime* GameDelayTime::getInstance()
if(!_instance)
_instance = new GameDelayTime();
_instance-&init();
void GameDelayTime::init()
DelayTimeDate* GameDelayTime::addDelayTimeCallBack( float delayTime,std::function&void()& callback )
auto delayTimeDate = DelayTimeDate::create(delayTime,callback);
_keyMap.push_back(delayTimeDate);
return delayTimeD
void GameDelayTime::removeDelayTimeCallBack( DelayTimeDate* delayTimeDate )
int size = _keyMap.size();
while (size--&0)
if(delayTimeDate == _keyMap.at(size) )
_keyMap.erase(_keyMap.begin()+size);
CC_SAFE_DELETE(delayTimeDate);
void GameDelayTime::UpdateTime(float time)
int size = _keyMap.size();
while (size--&0)
auto delayTimeDate = _keyMap.at(size);
if( delayTimeDate != nullptr )
bool isCallBack = delayTimeDate-&update(time);
if( isCallBack )
removeDelayTimeCallBack(delayTimeDate);
DelayTimeDate* DelayTimeDate::create( float delayTime,std::function&void()& callback )
DelayTimeDate* delayTimeDate = new DelayTimeDate();
delayTimeDate-&init(delayTime,callback);
return delayTimeD
bool DelayTimeDate::update(float time)
if( _time &= getDelayTime() )
if( callback )
callback();
return true;
return false;
GameDelayTime.cpp
& & &游戏主循环与定时器基本就这样了,我的实现比较简单。
简单出兵应用:
  简单的控制主循环实现游戏的暂停逻辑处理。目前是比较简单的实现,希望后续能想到更好的idea。
阅读(...) 评论()MFC定时器的使用 - CSDN博客
MFC定时器的使用
MFC提供了3个定时器函数来完成有关定时器功能:
UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)( HWND, UINT, UINT, DWORD) );
afx_msg void OnTimer( UINT nIDEvent );
BOOL KillTimer( int nIDEvent );
参数说明:
UINT nIDEvent:定时器的ID,给定时器唯一的身份验证,如果在一个程序中有多个定时器可以用这个ID来确定是那个定时器发送的消息。
UINT nElapse: 定义刷新时间,即间隔多长时间刷新一次,单位是毫秒。
void (CALLBACK EXPORT* lpfnTimer)( HWND, UINT, UINT, DWORD):
这个回调函数中实现刷新时所做的操作,如在数据库中读取数据。但是我们大多数时候不在这里实现,而是在OnTimer中。
SetTimer用来定义一个定时器的属性,如改定时器的ID,刷新时间,处理函数。
OnTimer实际时系统定义消息用来响应WM_TIMER消息,在这里可以实现对多定时器中的各个定时器分别响应,这里才时定时程序大展宏图的地方。
KillTimer用来结束一个定时器。
下面我们用一个例子来说明定时器的使用:
&& 这个例子用来实现一个简单的功能,就是在一个单文档程序中,每间隔5秒弹出一个消息框提示“定时器1”,每隔7秒弹出一个消息框提示“定时器2”。
&& 建立单文档程序略,一路Next。
=========================================================================
(1)在resource.h中定义两个定时器的ID
#define IDTIMER1
#define IDTIMER2
(2)在CMainFrame的OnCreate函数中定义两个定时器的属性。
SetTimer(TIMEID1,<span style="color:#8,0);
SetTimer(TIMEID2,<span style="color:#8,0);
(3) CMainFrame中对WM_TIMER进行响应。
oid CMainFrame::OnTimer(UINT nIDEvent)
// TODO: Add your message handler code here and/or call default
switch(nIDEvent) {
case TIMEID1:
AfxMessageBox(&定时器1!&);
case TIMEID2:
AfxMessageBox(&定时器2!&);
CFrameWnd::OnTimer(nIDEvent);
(4)在CMainFrame的析构函数中添加
KillTimer(IDTIMER1);
KillTimer(IDTIMER2);
==============================
当执行到程序的某一行代码时,需要添加计时器,就用这条语句:
SetTimer(1, 1000, NULL);
参数如下:
UINT_PTR SetTimer(UINT_PTR nIDEvent, UINT nElapse,
& void (CALLBACK* lpfnTimer)(HWND, UINT, UINT_PTR, DWORD));
设置好后计时器立马生效,1秒后计时器发生中断,在代码所在的类中进行捕捉:
1.在该类的消息中添加:
BEGIN_MESSAGE_MAP(CTab1, CDialog)
// CTab1是自己定义的一个类
ON_WM_TIMER()
END_MESSAGE_MAP()
2.所在的类中添加成员函数:
void OnTimer(UINT_PTR nIDEvent);
3.添加函数的代码,即捕捉后的执行代码:
void CTab1::OnTimer(UINT_PTR nIDEvent)
switch (nIDEvent)
// 计时器1
.... // 处理的代码
KillTimer(1);
// 删除此计时器,否则计时器中断完后会自动重新开始计时,到下一次中断时还会发生新的中断
// 计时器2
.... // 处理的代码
MessageBox(&default: KillTimer&);
KillTimer(nIDEvent);
本文已收录于以下专栏:
相关文章推荐
在计算机程序设计领域,有很多功能是周期性执行的,
&#160;&#160;&#160;&#160;&#160; 如:数据采集程序,系统时间的显示等。
数据采集:周期性地获得现场的物理量信息
系统时间的显示:周期性地获得...
先请看SetTimer这个API函数的原型
定时器概念:
使用定时器的目的是周期性的执行一个任务,或者是到某一时间去执行某一任务。本章用来处理断开连接超时的客户端,为此,将每个定时时间封装成定时器,并使用链表,时间轮(也是链表),堆等容器类...
巧妙地使用定时器能达到意想不到的效果,写界面的时候能实现渐变,也能帮助多线程控制等
我们知道,在VC的MFC中,已经为我们封装好了很多全面和强大的函数集,所以在MFC编程时,巧妙地调用MFC函数库可...
::本篇文章是论述上一篇&基于选择重传ARQ传输协议的数据重传机制方案设计&中定时器的实现
错误更正:
在本项目中,由于每个硬件传感器在软件系统中都对应一个传感器对象,数据传输以及重传...
1.1&#160; &#160;用WM_TIMER来设置定时器
先请看SetTimer这个API函数的原型
UINT_PTR&#160; &#160;SetTimer(
HWND&#160; &#160;hWnd,&#160; &#160;//&#160; &#160;窗口句柄 ...
CWnd类的SetTimer成员函数只能在CWnd类或其派生类中调用,而API函数SetTimer则没有这个限制,这是一个很重要的区别。
1、启动定时器。
&#160;&#160;&#160;&#160;&#160;&#160; 启动定时器就需要使用CWn...
用WM_TIMER来设置定时器&#160;
先请看SetTimer这个API函数的原型&#160;
// 窗口句柄
UINT_PTR...
对关注性能的程序开发人员而言,一个好的计时部件既是益友,也是良师。计时器既可以作为程序组件帮助程序员精确的控制程序进程,又是一件有力的调试武器,在有经验的程序员手里可以尽快的确定程序的性能瓶颈,或者对...
在MFC中经常我们需要对界面进行刷新更新数据或者状态,这就需要用到定时器,其实现函数为OnTimer,下面对其用法步骤(基于VS2010)进行简要说明:
他的最新文章
讲师:吴岸城
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)(Visual C++)游戏开发笔记之八——基础动画显示(二)游戏循环的使用
在笔记七中我们讲解了用定时器来产生动画的效果。定时器的使用固然简单方便,但是事实上这样的方法仅适合用在显示简易动画及小型的游戏程序中。因为一般而言,游戏本身需要显示顺畅的游戏画面,使玩家感觉不到延迟的状态。基本游戏画面必须在一秒钟之内更新至少25次以上,这一秒钟内程序还必须进行消息的处理和大量数学运算甚至音效的输出等操作。而使用定时器的消息来驱动这些操作,往往达不到所要求的标准,不然就会产生画面显示不顺畅和游戏响应时间太长的情况。
这里我们提出一种游戏循环的概念,游戏循环是将原先程序中的消息循环加以修改,方法是判断其中的内容目前是否有要处理的消息,如果有则进行处理,否则按照设定的时间间隔来重绘画面。下面是接下来一段游戏循环的程序代码:
//游戏循环&&
&&& while( msg.message!=WM_QUIT )&&&&&&&&&&&&&& //注释点1(详细内容见下)&&
&&&&&&& if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )&&&&&& //注释点2(详细内容见下)&&
&&&&&&& {&
&&&&&&&&&&& TranslateMessage( &msg );&
&&&&&&&&&&& DispatchMessage( &msg );&
&&&&&&& }&
tNow = GetTickCount();&&&&&&&&&&&&&&&&&&&&&&& //注释点3&&
if(tNow-tPre &= 100)&&&&&&&&&&&&&&&&&& //注释点4&&
MyPaint(hdc);&
//游戏循环
&&& while( msg.message!=WM_QUIT )&&&&&&&&&&&&&& //注释点1(详细内容见下)
&&&&&&& if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )&&&&&& //注释点2(详细内容见下)
&&&&&&&&&&& TranslateMessage( &msg );
&&&&&&&&&&& DispatchMessage( &msg );
tNow = GetTickCount();&&&&&&&&&&&&&&&&&&&&&&& //注释点3
if(tNow-tPre &= 100)&&&&&&&&&&&&&&&&&& //注释点4
MyPaint(hdc);
我们来讲解一下游戏循环片段中的几个重点。
&1&注释点1:当收到的msg.message不是窗口结束消息WM_QUIT,则继续运行循环,其中msg是一个MSG的消息结构,其结构成员message则是一个消息类型的代号。
&2&注释点2:使用PeekMessage()函数来检测目前是否有需要处理的消息,若检测到消息(包含WM_QUIT消息)则会返回一个非&0&值,否则返回&0&。因此在游戏循环中,若检测到消息便进行消息的处理,否则运行else叙述之后的程序代码。这里我们要注意的是,PeekMessage()函数不能用原先消息循环的条件GetMessage()取代,因为GetMessage()函数只有在取得WM_QUIT消息时才会返回&0&,其他时候则是返回非&0&值或&-1&(发生错误时)
&3&注释点3:GetTickCount()函数会取得开始运行到目前所经过的时间,单位是毫秒(milliseconds)。& 之前我理解错了,在这里感谢worldy的指出我的错误。
DWORD GetTickCount()&&& //取得系统开始到目前经过的时间
这里取得时间的目的主要是可以搭配接下来的判断式,用来调整游戏运行的速度,使得游戏不会因为运行计算机速度的不同而跑得太快或者太慢。
&4&注释点4:if条件式中,&tPre&记录前次绘图的时间,而&tNow-tRre&则是计算上次绘图到这次循环运行之间相差多少时间。这里设置为若相差40个单位时间以上则再次进行绘图的操作,通过这个数值的控制可以调整游戏运行的速度。这里设定40个单位时间(微秒)的原因是,因为每隔40个单位进行一次绘图的操作,那么1秒钟大约重绘窗口次刚好可以达到期望值。
由于循环的运行速度远比定时器发出时间信号来得快,因此使用游戏循环可以更精准地控制程序运行速度并提高每秒钟画面重绘的次数。
了解了游戏循环使用的基本概念之后,接下来的范例将以游戏循环的方法进行窗口的连续贴图,更精确地制作游戏动画效果。
#include &stdafx.h&&&
#include &stdio.h&&&
//全局变量声明&&
HINSTANCE hI&
HBITMAP man[7];&
HDC& hdc,&
HWND&&& hW&
DWORD&& tPre,tNow,tC&&&&&&&&&&&&&&&& //声明三个函数来记录时间,tPre记录上一次绘图的时间,tNow记录此次准备绘图的时间,tCheck记录每秒开始的时间&&
int& num,frame,&&&&&&&&&&&&&&&&&&& //num用来记录图号,frame用来累加每次画面更新的次数,fps(frame per second)用来记录每秒画面更新的次数&&
//全局函数的声明&&
ATOM&&&& MyRegisterClass&
(HINSTANCE hInstance);&
BOOL&&&& InitInstance&
(HINSTANCE, int);&
LRESULT CALLBACK&&& WndProc(HWND, UINT, ARAM,&&
void&&&& MyPaint(HDC hdc);&
//***WinMain函数,程序入口点函数**************************************&&
int APIENTRY WinMain(HINSTANCE hInstance,&
&&&&&&&&&&&&&&&&&&&& HINSTANCE hPrevInstance,&
&&&&&&&&&&&&&&&&&&&& LPSTR&&&& lpCmdLine,&
&&&&&&&&&&&&&&&&&&&& int&&&&&& nCmdShow)&
MyRegisterClass(hInstance);&
//运行初始化函数&&
if (!InitInstance (hInstance, nCmdShow))&&
return FALSE;&
#include &stdafx.h&
#include &stdio.h&
//全局变量声明
HINSTANCE hI
HBITMAP man[7];
DWORD&tPre,tNow,tC&&&&&&&&&&&&&&&& //声明三个函数来记录时间,tPre记录上一次绘图的时间,tNow记录此次准备绘图的时间,tCheck记录每秒开始的时间
int& num,frame,&&&&&&&&&&&&&&&&&&& //num用来记录图号,frame用来累加每次画面更新的次数,fps(frame per second)用来记录每秒画面更新的次数
//全局函数的声明
ATOM& MyRegisterClass
(HINSTANCE hInstance);
BOOL& InitInstance
(HINSTANCE, int);
LRESULT CALLBACK&WndProc(HWND, UINT, WPARAM,
void& MyPaint(HDC hdc);
//***WinMain函数,程序入口点函数**************************************
int APIENTRY WinMain(HINSTANCE hInstance,
&&&&&&&&&&&&&&&&&&&& HINSTANCE hPrevInstance,
&&&&&&&&&&&&&&&&&&&& LPSTR&&&& lpCmdLine,
&&&&&&&&&&&&&&&&&&&& int&&&&&& nCmdShow)
MyRegisterClass(hInstance);
//运行初始化函数
if (!InitInstance (hInstance, nCmdShow))
return FALSE;
GetMessage(&msg,NULL,NULL,NULL);&& //感谢xiaoxiangp的提醒,需要在进入消息循环之前初始化msg,避免了死循环发生的可能性。&&
//游戏循环&&
&&& while( msg.message!=WM_QUIT )&
&&&&&&& if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )&
&&&&&&& {&
&&&&&&&&&&& TranslateMessage( &msg );&
&&&&&&&&&&& DispatchMessage( &msg );&
&&&&&&& }&
tNow = GetTickCount();&
if(tNow-tPre &= 100)&&&&&&& //当此次循环运行与上次绘图时间相差0.1秒时再进行重绘操作&&
MyPaint(hdc);&
return msg.wP&
//****设计一个窗口类,类似填空题,使用窗口结构体*************************&&
ATOM MyRegisterClass(HINSTANCE hInstance)&
WNDCLASSEX&
wcex.cbSize = sizeof(WNDCLASSEX);&&
wcex.style&& = CS_HREDRAW |&&
CS_VREDRAW;&
wcex.lpfnWndProc&&& = (WNDPROC)WndP&
wcex.cbClsExtra& = 0;&
wcex.cbWndExtra& = 0;&
wcex.hInstance&& = hI&
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] = &&;&
hInst = hI&
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);&
frame = 0;&
MyPaint(hdc);&
return TRUE;&
//****自定义绘图函数*********************************&&
// 1.计算与显示每秒画面更新次数&&
// 2.按照图号顺序进行窗口贴图&&
void MyPaint(HDC hdc)&
char str[40] = &&;&
if(num == 7)&
frame++;&&&&&&&&&&& //画面更新次数加1&&
if(tNow - tCheck &= 1000)&&&&&&&&&&&&&& //判断此次绘图时间由前一秒算起是否已经达到1秒钟的时间间隔。若是,则将目前的&#39;frame&#39;值赋给&fps&,表示这一秒内所更新的画面次数,然后将&frame&值回0,并重设下次计算每秒画面数的起始时间&iCheck&。&&
frame = 0;&
tCheck = tN&
SelectObject(mdc,man[num]);&&&&&&&& //选用要更新的图案到mdc中,再输出显示每秒画面更新次数的字符串到mdc上,最后将mdc的内容贴到窗口中。&&
sprintf(str,&每秒显示 %d个画面&,fps);&
TextOut(mdc,0,0,str,strlen(str));&
BitBlt(hdc,0,0,600,450,mdc,0,0,SRCCOPY);&
tPre = GetTickCount();&&&& //记录此次绘图时间,供下次游戏循环中判断是否已经达到画面更新操作设定的时间间隔。&&
//******消息处理函数*********************************&&
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,&&
WPARAM wParam, LPARAM lParam)&
switch (message)&
case WM_DESTROY:&&&& //窗口结束消息&&
DeleteDC(mdc);&
for(i=0;i&7;i++)&
DeleteObject(man[i]);&
ReleaseDC(hWnd,hdc);&
PostQuitMessage(0);&
default:&&&& //其他消息&&
return DefWindowProc(hWnd,&&
message, wParam, lParam);&
&& return 0;&
GetMessage(&msg,NULL,NULL,NULL);&& //感谢xiaoxiangp的提醒,需要在进入消息循环之前初始化msg,避免了死循环发生的可能性。
//游戏循环
&&& while( msg.message!=WM_QUIT )
&&&&&&& if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )
&&&&&&&&&&& TranslateMessage( &msg );
&&&&&&&&&&& DispatchMessage( &msg );
tNow = GetTickCount();
if(tNow-tPre &= 100)&&&&&&& //当此次循环运行与上次绘图时间相差0.1秒时再进行重绘操作
MyPaint(hdc);
return msg.wP
//****设计一个窗口类,类似填空题,使用窗口结构体*************************
ATOM MyRegisterClass(HINSTANCE hInstance)
WNDCLASSEX
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style& = CS_HREDRAW |
CS_VREDRAW;
wcex.lpfnWndProc&= (WNDPROC)WndP
wcex.cbClsExtra& = 0;
wcex.cbWndExtra& = 0;
wcex.hInstance& = hI
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] = &&;
hInst = hI
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);
frame = 0;
MyPaint(hdc);
return TRUE;
//****自定义绘图函数*********************************
// 1.计算与显示每秒画面更新次数
// 2.按照图号顺序进行窗口贴图
void MyPaint(HDC hdc)
char str[40] = &&;
if(num == 7)
frame++;&&&&&&&& //画面更新次数加1
if(tNow - tCheck &= 1000)&&&&&&&&&&&&&& //判断此次绘图时间由前一秒算起是否已经达到1秒钟的时间间隔。若是,则将目前的&#39;frame&#39;值赋给&fps&,表示这一秒内所更新的画面次数,然后将&frame&值回0,并重设下次计算每秒画面数的起始时间&iCheck&。
frame = 0;
tCheck = tN
SelectObject(mdc,man[num]);&&&&&&&& //选用要更新的图案到mdc中,再输出显示每秒画面更新次数的字符串到mdc上,最后将mdc的内容贴到窗口中。
sprintf(str,&每秒显示 %d个画面&,fps);
TextOut(mdc,0,0,str,strlen(str));
BitBlt(hdc,0,0,600,450,mdc,0,0,SRCCOPY);
tPre = GetTickCount();&&&& //记录此次绘图时间,供下次游戏循环中判断是否已经达到画面更新操作设定的时间间隔。
//******消息处理函数*********************************
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
switch (message)
case WM_DESTROY:& //窗口结束消息
DeleteDC(mdc);
for(i=0;i&7;i++)
DeleteObject(man[i]);
ReleaseDC(hWnd,hdc);
PostQuitMessage(0);
default:& //其他消息
return DefWindowProc(hWnd,
message, wParam, lParam);
&& return 0;
程序的运行结果如下图:
当然想要得到上述动画,我们需要把几幅位图文件放到工程文件夹下。
这个范例中我们设定的画面更新时间间隔为0.1秒,所以每秒钟最多会更新10次画面。不过如果在运行这个例子的时候同时也运行其他的程序,那么CPU必须马上出去处理所开启的其他程序,因此可能会使得每秒画面的更新次数稍稍下降。
笔记八到这里就结束了。
本节源代码请点击这里下载:【Visual C++】Code_Note_8&
请大家继续关注【Visual C++】游戏开发笔记系列。
非常希望能与大家一起交流,共同学习和进步。
最后,谢谢大家的支持~~~
摘自& 枫落★流年}

我要回帖

更多关于 js定时器嵌套循环 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信