因为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. day63-webservice 09.jquery调用ajax

    WebService可以有很多种调用方式,除了之前说的,还可以有jquery.拿原生的Ajax做调用,拿jquery怎么调用啊?原生的能调,jquery指定也能调.原生的Ajax是通过网页直接点HTM ...

  2. Arduino-IIC-Wire.h

    前言:Wire.h是Arduino的IIC库. 一.Wire库函数 Wire.begin() Wire.requestFrom() Wire.beginTransmission() Wire.endT ...

  3. mysql在第一次查询的时候很慢,第二次查询就比较快的原因?

    1.默认 query_cache 是打开的 你使用 show global variables like '%query_cache%'; 确认一下有没有打开,如果打开了.第一次查询读数据文件,第二次 ...

  4. Android 低功耗蓝牙的多设备连接与数据接收,简单实现

    在网络层,互联网提供所有应用程序都要使用的两种类型的服务,尽管目前理解这些服务的细节并不重要,但在所有TCP/IP概述中,都不能忽略他们: 无连接分组交付服务(Connectionless Packe ...

  5. WinForm进程 线程

    进程主要调用另一程序,线程 分配工作. 一.进程: 进程是一个具有独立功能的程序关于某个数据集合的一次运行活动.它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体.Process 类,用来操 ...

  6. 使用Micrisoft.net设计方案 第一章 企业解决方案中构建设计模式

    第一章企业解决方案中构建设计模式 我们知道的系统总是由简单到复杂,而不是直接去设计一个复杂系统.如果直接去设计一个复杂系统,结果最终会导致失败.在设计系统的时候,先设计一个能够正常工作的系统,然后在此 ...

  7. [Offer收割]编程练习赛38

    漏写的数字 #pragma comment(linker, "/STACK:102400000,102400000") #include<stdio.h> #inclu ...

  8. 23个Python爬虫开源项目代码:爬取微信、淘宝、豆瓣、知乎、微博等

    来源:全球人工智能 作者:SFLYQ 今天为大家整理了23个Python爬虫项目.整理的原因是,爬虫入门简单快速,也非常适合新入门的小伙伴培养信心.所有链接指向GitHub,祝大家玩的愉快 1.Wec ...

  9. SQL Server-聚焦过滤索引提高查询性能

    前言 这一节我们还是继续讲讲索引知识,前面我们讲了聚集索引.非聚集索引以及覆盖索引等,在这其中还有一个过滤索引,通过索引过滤我们也能提高查询性能,简短的内容,深入的理解,Always to revie ...

  10. PhotoZoom放大的图片效果怎么样?清不清晰?

    PhotoZoom是一款使用了革命性技术.效果最好的图像无损放大工具.它可以对图片进行放大而没有锯齿,不会失真,让您无与伦比完美放大图像质量. PhotoZoom Pro使用了S-Spline Max ...