Cocos2d-x 动手实现游戏主循环
因为Cocos2d-x封装的非常好,所以对于非常多新手,他们仅仅知道先new一个场景,在场景上加入布景或精灵,然后用Director的runWithScene便能够执行游戏了。假设给一个精灵加个动作,精灵就会动,假设给布景层加入个定时器,游戏会定时执行。你知道为什么会这样吗?
作为一个游戏开发人员,我认为进入游戏这一行业之前,一定要先搞清楚“游戏主循环”这个东东,可惜我到如今才来研究这个东东。也许网上关于Cocos2d-x游戏主循环的解说一大把,可是这篇文章,我会教你怎么来实现游戏主循环。
一、了解Cocos2d-x游戏的入口
windows应用程序入口一般都在main(),我们Cocos2d-x找到main.cpp文件,里面的代码非常easy:
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine); // create the application instance
AppDelegate app;
return Application::getInstance()->run();
}
好了,我们知道了Application类里面的run函数就是入口了。找到Application.cpp文件,我截取run函数最重要的那部分代码:
while(!glview->windowShouldClose())
{
QueryPerformanceCounter(&nNow);
if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)
{
nLast.QuadPart = nNow.QuadPart; director->mainLoop();
glview->pollEvents();
}
else
{
Sleep(0);
}
}
看到没,这里有一个死循环,粗略地看,也就是这种:_animationInterval是我们设定的循环间隔,每次前后两个时间的差大于这个间隔,就运行一次主循环director->mainLoop(),小于这个间隔呢,就一直获取当前的时间,直到大于这个间隔。
大概就是这样,为什么程序会一直运行呢?接下来我们来自己动手实现下面这个循环。
二、Windows性能计数器(Performance Counter)
在run函数中,我们发现每次时间差大于设定的间隔,就会运行游戏主循环,那么这个时间差是哪里来的呢?就是这个东东:QueryPerformanceCounter,选中QueryPerformanceCounter按F12,看看是何方神圣:
//
// Performance counter API's
// WINBASEAPI
BOOL
WINAPI
QueryPerformanceCounter(
_Out_ LARGE_INTEGER * lpPerformanceCount
); WINBASEAPI
BOOL
WINAPI
QueryPerformanceFrequency(
_Out_ LARGE_INTEGER * lpFrequency
);
也就是说,这两个函数事实上是Windows API来的。
QueryPerformanceCounter():返回高精度性能计数器的值,QueryPerformanceCounter确切的精确计时的最小单位是与系统有关的,所以必须查询系统以得到QueryPerformanceCounter返回的滴答声的频率。
QueryPerformanceFrequency()则提供了这个频率值,返回每秒滴答声的个数。
计算两个时间的间隔,就是用QueryPerformanceCounter()先后获取两个时间,这两个时间的间隔再除以时钟频率,就是真正的时间差了。
再看类型LAGER_INTEGER:
#if defined(MIDL_PASS)
typedef struct _LARGE_INTEGER {
#else // MIDL_PASS
typedef union _LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
} DUMMYSTRUCTNAME;
struct {
DWORD LowPart;
LONG HighPart;
} u;
#endif //MIDL_PASS
LONGLONG QuadPart;
} LARGE_INTEGER;
LARGE_INTEGER既能够是一个8字节长的整型数(LONGLONG),也能够是两个4字节长的整型数的联合结构,详细使用方法依据编译器是否支持64位而定。
三、详细实现主循环
往事具备,仅仅欠东风。有了上面那些知识,我们就能够自己动手实现了。
用VS2012新建一个win32控制台project,打开main.cpp文件開始写程序了。
先创建一个MainLoop类:
class MainLoop
{
public:
MainLoop():timeCount(0){}
void setAnimationInterval(double interval);
void run(); private:
LARGE_INTEGER _animationInteval;
unsigned timeCount;
}; void MainLoop::setAnimationInterval(double interval)
{
LARGE_INTEGER nFreq;
QueryPerformanceFrequency(&nFreq);
_animationInteval.QuadPart = (LONGLONG)(interval * nFreq.QuadPart);
} void MainLoop::run()
{
LARGE_INTEGER nFreq;
LARGE_INTEGER nBeginTime;
LARGE_INTEGER nEndTime; QueryPerformanceFrequency(&nFreq); // 获取机器内部计时器的时钟频率
QueryPerformanceCounter(&nBeginTime); // 获得第一次计数 while (1) // 死循环
{
QueryPerformanceCounter(&nEndTime); // 获得第二次计数
if (nEndTime.QuadPart - nBeginTime.QuadPart > _animationInteval.QuadPart) // 两次计数差大于指定间隔则运行
{
timeCount++;
printf("%d\n", timeCount);
nBeginTime = nEndTime;
}
}
}
这个类能够设置时间间隔,当前后两次时间差大于该间隔的时候,就输出一次timeCount,timeCount就是计数器。
int _tmain(int argc, _TCHAR* argv[])
{
MainLoop loop;
loop.setAnimationInterval(1);
loop.run(); system("pause");
return 0;
}
在main函数中,我们先设置时间间隔为1秒,開始run,这时能够看到,每隔1秒钟,控制台就会输出计数器:
这就是我们要的循环了,想一下,时间间隔越小,计数器就加的越快,当时间间隔为1/60时,就跟Cocos2d-x的一样了。
回去看看Application的代码,是不是认为非常像非常像。仅仅只是在Application中运行的不是计数器叠加,而是director->mainLoop(),也就是所谓的游戏主循环。
游戏主循环的分析就到这里了,网上充斥着大量一样的文章,ctrl+c和ctrl+v太简单了,希望我这一篇有别于其它Cocos2d-x游戏主循环的文章能帮到你。
Cocos2d-x 动手实现游戏主循环的更多相关文章
- Cocos2d-x 3.2 学习笔记(十六)保卫萝卜 游戏主循环与定时器
保卫萝卜~想法一直存在于想法,实战才是硬道理!有想法就去实现,眼高手低都是空谈. 一.游戏主循环GameSchedule 主循环是游戏处理逻辑,控制游戏进度的地方,处理好主循环是很重要的 ...
- 游戏主循环(Game Loop)
游戏主循环是游戏的心跳,一般使用while循环进行主动刷新. 一次循环由获取用户输入.更新游戏状态.处理AI.播放音乐和绘制画面组成. 这些行为可以分成两类: update_game(); // 更新 ...
- [UE4]游戏主循环
游戏的运行模型 理解游戏的运行模型,对处理很多游戏错误有非常大的帮助. 游戏是有一个主循环的.那么游戏主循环做了什么事情呢? 游戏主循环一次就表示一帧,游戏主循环包括:接受输入.处理游戏逻辑.渲染.S ...
- Vue+WebPack游戏设计:自动背景贴图和游戏主循环的实现
- cocos2d-x游戏引擎核心之三——主循环和定时器
一.游戏主循环 在介绍游戏基本概念的时候,我们曾介绍了场景.层.精灵等游戏元素,但我们却故意避开了另一个同样重要的概念,那就是游戏主循环,这是因为 Cocos2d 已经为我们隐藏了游戏主循环的实现.读 ...
- Cocos2dx源码赏析(1)之启动流程与主循环
Cocos2dx源码赏析(1)之启动流程与主循环 我们知道Cocos2dx是一款开源的跨平台游戏引擎,而学习开源项目一个较实用的办法就是读源码.所谓,"源码之前,了无秘密".而笔者 ...
- 辛巴学院-Unity-剑英的c#提高篇(一)主循环
这是测试版 辛巴学院:正大光明的不务正业. 最近刚刚离开了我服务了三年多的公司,因为一个无数次碰到的老问题,没钱了. 之前不知道做什么好的时候,机缘巧合之下和哒嗒网络的吴总聊了一下,发现了vr gam ...
- Update主循环、状态机的实现
从写一段程序,到写一个app,写一个游戏,到底其中有什么不同呢?一段程序的执行时间很短,一个应用的执行时间很长,仅此而已. 游戏中存在一个帧的概念. 这个概念大家都知道,类比的话,它就是电影胶卷的 ...
- 1 cocos2dx源码分析-程序启动与主循环
1 启动 在iOS系统中,由main函数启动默认调用了AppController main.m NSAutoreleasePool * pool = [[NSAutoreleasePool ...
随机推荐
- hdoj--3072--Intelligence System(scc+缩点+数据去重)
Intelligence System Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...
- B1970 [Ahoi2005]Code 矿藏编码 暴力模拟
小詹从哪整出来这么多水题?%%%这个题用栈模拟一下,然后直接暴力就行了...一开始还没想到,用的dfs,我太菜了... 题干: Description 依次对每份进行编码,得S1,S2,S3,S4.该 ...
- mysql查询orderby
--按某一字段分组取最大(小)值所在行的数据 /* 数据如下: name val memo a 2 a2(a的第二个值) a 1 a1--a的第一个值 a 3 a3:a的 ...
- 给统计人讲Python(1)_科学计算库-Numpy
本地代码是.ipynb格式的转换到博客上很麻烦,这里展示部分代码,了解更多可以查看我的git-hub:https://github.com/Yangami/Python-for-Statisticia ...
- Java常见面试题02-方法重写和方法重载的区别?方法重载能改变返回值类型吗?
方法重写和方法重载的区别?方法重载能改变返回值类型吗? A:Override方法重写和Overload方法重载的区别? Overload是否可以改变返回值类型?可以 方法重写 • 子类中 ...
- 浅谈Python Web 框架:Django, Twisted, Tornado, Flask, Cyclone 和 Pyramid
Django Django 是一个高级的 Python Web 框架,支持快速开发,简洁.实用的设计.如果你正在建一个和电子商务网站相似的应用,那你应该选择用 Django 框架.它能使你快速完成工作 ...
- Hibernate中实体对象的状态
实体对象的状态 这里的实体对象是指Hibernate的O/R映射关系中的域对象(即O/R中的O).实体对象的生命周期是指实体对象由产生到被GC回收的一段过程,实体对象的生命周期包括3种状态:自由状态( ...
- 给<hr/>添加样式
点线式 破折线式 直线式 双线式 脊线式 槽线式 内嵌效果的 突起效果的 border-top:10px 设置水平线的大小 <hr style=" border-top:5px dot ...
- Spring aop(实验写法)
1. 创建通知:定义一个接口 Public interface Sleepable { voidsleep(); }然后写一个Human类,他实现了这个接口 publicHuman implement ...
- Teamwork-六月上旬心得体会
六月上旬心得体会 在五月末的时候,老师针对我们团队的状况提出了几点建议和解决方案,而这半个月里,我们尝试性地运用了其中的几件工具与方法. 1.燃尽图与每日总结 我们采用的是<构建之法>书中 ...