Cocos2d-x 动手实现游戏主循环

时间:2024-10-29 18:05:20

因为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秒钟,控制台就会输出计数器:

Cocos2d-x 动手实现游戏主循环



这就是我们要的循环了,想一下,时间间隔越小,计数器就加的越快,当时间间隔为1/60时,就跟Cocos2d-x的一样了。

回去看看Application的代码,是不是认为非常像非常像。仅仅只是在Application中运行的不是计数器叠加,而是director->mainLoop(),也就是所谓的游戏主循环。

游戏主循环的分析就到这里了,网上充斥着大量一样的文章,ctrl+c和ctrl+v太简单了,希望我这一篇有别于其它Cocos2d-x游戏主循环的文章能帮到你。