因为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 动手实现游戏主循环的更多相关文章

  1. Cocos2d-x 3.2 学习笔记(十六)保卫萝卜 游戏主循环与定时器

    保卫萝卜~想法一直存在于想法,实战才是硬道理!有想法就去实现,眼高手低都是空谈.   一.游戏主循环GameSchedule      主循环是游戏处理逻辑,控制游戏进度的地方,处理好主循环是很重要的 ...

  2. 游戏主循环(Game Loop)

    游戏主循环是游戏的心跳,一般使用while循环进行主动刷新. 一次循环由获取用户输入.更新游戏状态.处理AI.播放音乐和绘制画面组成. 这些行为可以分成两类: update_game(); // 更新 ...

  3. [UE4]游戏主循环

    游戏的运行模型 理解游戏的运行模型,对处理很多游戏错误有非常大的帮助. 游戏是有一个主循环的.那么游戏主循环做了什么事情呢? 游戏主循环一次就表示一帧,游戏主循环包括:接受输入.处理游戏逻辑.渲染.S ...

  4. Vue+WebPack游戏设计:自动背景贴图和游戏主循环的实现

  5. cocos2d-x游戏引擎核心之三——主循环和定时器

    一.游戏主循环 在介绍游戏基本概念的时候,我们曾介绍了场景.层.精灵等游戏元素,但我们却故意避开了另一个同样重要的概念,那就是游戏主循环,这是因为 Cocos2d 已经为我们隐藏了游戏主循环的实现.读 ...

  6. Cocos2dx源码赏析(1)之启动流程与主循环

    Cocos2dx源码赏析(1)之启动流程与主循环 我们知道Cocos2dx是一款开源的跨平台游戏引擎,而学习开源项目一个较实用的办法就是读源码.所谓,"源码之前,了无秘密".而笔者 ...

  7. 辛巴学院-Unity-剑英的c#提高篇(一)主循环

    这是测试版 辛巴学院:正大光明的不务正业. 最近刚刚离开了我服务了三年多的公司,因为一个无数次碰到的老问题,没钱了. 之前不知道做什么好的时候,机缘巧合之下和哒嗒网络的吴总聊了一下,发现了vr gam ...

  8. Update主循环、状态机的实现

    从写一段程序,到写一个app,写一个游戏,到底其中有什么不同呢?一段程序的执行时间很短,一个应用的执行时间很长,仅此而已. 游戏中存在一个帧的概念.   这个概念大家都知道,类比的话,它就是电影胶卷的 ...

  9. 1 cocos2dx源码分析-程序启动与主循环

        1 启动   在iOS系统中,由main函数启动默认调用了AppController main.m NSAutoreleasePool * pool = [[NSAutoreleasePool ...

随机推荐

  1. sublime-text 编译C

    sublime的优点多多. 先下好sublime-text 如果不会下载 在ubuntu 下输入sudo apt-cache search sublime 查找到合适的安装包后apt-get inst ...

  2. php如何将网上的图片下载到本地

    <?phpheader("Content-Type: application/force-download");header("Content-Dispositio ...

  3. [luogu P5349] 幂 解题报告 (分治FFT)

    interlinkage: https://www.luogu.org/problemnew/show/P5349 description: solution: 设$g(x)=\sum_{n=0}^{ ...

  4. C#解除某类警告。。。。。。。。。。

    C#预处理器指令取消不必要的警告 今天将自己写的一个类库生成一个DLL后,想把注释也加进去.... 方法:在属性->生成选项卡->XML文档文件(勾选)(生成的文件名不能修改,使用时必须跟 ...

  5. Android GoogleMap 谷歌地图从零开始

    说明 由于国内使用v2最新的谷歌地图有很多限制,所有如果要在真机上测试运行要做一些准备 准备1: vpn必不可少啦 推荐cloud vpn或者betternet都是不错的免费vpn 准备2: 由于最新 ...

  6. Vue报错笔记

    1.错误信息:[Vue warn]: Property or method "object" is not defined on the instance but referenc ...

  7. 数据仓库模型建设基础及kimball建模方法总结

    观察数据的角度称之为维.决策数据市多为数据,多维数据分析是决策分析的组要内容. OLAP是在OLTP的基础上发展起来的,OLTP是以数据库为基础的,面对的是操作人员和底层管理人员,对基本数据进行查询和 ...

  8. 使用光盘作为yum源安装ifconfig等网络命令

    # mkdir -p /mnt/cdrom# 如果是光驱:mount -t iso9660 /dev/cdrom /mnt/cdrom/# 如果是ISO:mount -o loop /usr/loca ...

  9. vue1 到 vue2 v-el变成ref

    vue1的写法 div class="menu-wrapper" v-el="menu-wrapper"> <ul class="menu ...

  10. 【ES6】 Promise / await / async的使用

    为什么需要在项目中引入promise? 项目起因:我们在页面中经常需要多次调用接口,而且接口必须是按顺序串联调用 (即A接口调用完毕,返回数据后,再调用B接口) 这样就会造成多次回调,代码长得丑,而且 ...