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

由于Cocos2d-x封装的很好,所以对于很多新手,他们只知道先new一个场景,在场景上添加布景或精灵,然后用Director的runWithScene便可以运行游戏了。如果给一个精灵加个动作,精灵就会动,如果给布景层添加个定时器,游戏会定时执行。你知道为什么会这样吗?

作为一个游戏开发者,我觉得进入游戏这一行业之前,一定要先搞清楚“游戏主循环”这个东东,可惜我到现在才来研究这个东东。或许网上关于Cocos2d-x游戏主循环的讲解一大把,但是这篇文章,我会教你怎么来实现游戏主循环。

一、了解Cocos2d-x游戏的入口

windows应用程序入口一般都在main(),我们Cocos2d-x找到main.cpp文件,里面的代码很简单:

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控制台工程,打开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游戏主循环的文章能帮到你。

时间: 2024-10-10 01:20:13

Cocos2d-x 动手实现游戏主循环的相关文章

4.帧循环(游戏主循环),schedule

 1 概述 游戏乃至图形界面的本质是不断地绘图,然而绘图并不是随意的,任何游戏都需要遵循一定的规则来呈现出来,这些规则就体现为游戏逻辑.游戏逻辑会控制游戏内容,使其根据用户输入和时间流逝而改变.因此,游戏可以抽象为不断地重复. 2 以下动作: A 处理用户输入 B 处理定时事件 C 绘图 游戏主循环就是这样的一个循环,它会反复执行以上动作,保持游戏进行下去,直到玩家退出游戏. CCDirector::mainLoop()方法,这个方法负责调动定时器,绘图,发送全局通知,并处理内存回收池.该方

我的Cocos2d-x学习笔记(九)游戏帧循环(游戏主循环)

游戏运行时候会不断按照游戏逻辑规则重新绘图,反复处理用户输入.处理定时事件.绘图,直到游戏结束. Cocos2d-x引擎也是通过不断绘图来进行游戏的,默认的帧率在AppDelegate.cpp中显示为60帧每秒,也就是每秒执行了60次用户输入.定时时间.绘图等. 抄录Cocos2d-x高级教程中内容如下: 游戏乃至图形界面的本质是不断地绘图,然而绘图并不是随意的,任何游戏都需要遵循一定的规则来呈现出来,这些规则就体现为游戏逻辑. 游戏逻辑会控制游戏内容,使其根据用户输入和时间流逝而改变.因此,游

游戏主循环知识积累

1. 引言 游戏主循环是每个游戏的心跳,输送着整个游戏需要的养分.不幸的是没有任何一篇好的文章来指导一个菜鸟游戏程序员如何为自己的程序供养.不过不用担心,因为你刚好不小心看到了这篇,也是唯一一篇给予这个话题足够重视的文章. 由于我身为游戏程序员,我见过许许多多的手机小游戏的代码.这些代码给我展示了五彩缤纷的游戏主循环实现方法.你可能要问:"这么简单的一个小玩意还能做到千奇百怪?" 事实就是这样,我就会在此文中讨论一些主流实现的优缺点,并且给你介绍在我看来最好的输送养分的解决方案. 游戏

游戏主循环脚手架

在开头,我们知道在一个游戏应用中,游戏是在游戏主循环里面运行的.Flame插件已经提供了可以直接使用的游戏主循环脚手架,要使用这个脚手架,就要用到Flame的游戏(Game)抽象类. 创建一个名称为box-game.dart的新文件,然后开始编写BoxGame类,. import 'dart:ui'; import 'package:flame/game.dart'; class BoxGame extends Game { void render(Canvas canvas) { // TOD

cocos2d-x游戏开发之游戏主循环

首先还是就我个人的理解,讲讲游戏引擎的处理流程. 其实游戏逻辑简单化就是一个死循环,如下: 1 2 bool game_is_running = true; 3 4 while( game_is_running ) { 5 update_game(); 6 display_game(); 7 } 我们所看到的游戏画面,游戏音乐,以及一些触控,输入等.在逻辑上就是这么一个死循环.这个循环一直在跑,期间会处理一些列的事件,简化之就是上面的两个函数. cocos2d-x引擎也是如此,所有的逻辑都是在这

Cocos2d JS 之消灭星星(五) 游戏主场景

1 /* 2 * 游戏主场景 3 */ 4 var GameMainScene = ccui.Layout.extend( 5 { 6 ctor:function() 7 { 8 this._super(); 9 this.zinit(); 10 this.setTopInfor(); 11 this.addStarLayout(); 12 }, 13 //游戏主场景顶部显示信息 14 setTopInfor:function() 15 { 16 var gameTopInfo = new Ga

Cocos2d JS 之消灭星星(四) 游戏主场景顶部显示

1 /* 2 * 游戏主场景顶部显示信息 3 */ 4 var GameTopInformation = ccui.Layout.extend( 5 { 6 size:null, 7 isPause:false,//是否暂停游戏 8 maxScoreLabel:null,//最高纪录 9 getScoreNum:null,//当前得分 10 currentLevel:null,//当前关卡 11 ctor:function() 12 { 13 this._super(); 14 this.zin

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

Cocos2dx源码赏析(1)之启动流程与主循环 我们知道Cocos2dx是一款开源的跨平台游戏引擎,而学习开源项目一个较实用的办法就是读源码.所谓,"源码之前,了无秘密".而笔者从事的也是游戏开发工作,因此,通过梳理下源码的脉络,来加深对Cocos2dx游戏引擎的理解. 既然,Cocos2dx是跨平台的,那么,就有针对不同平台运行的入口以及维持引擎运转的"死循环".下面,就分别从Windows.Android.iOS三个平台说明下Cocos2dx从启动到进入主循环

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

这是测试版 辛巴学院:正大光明的不务正业. 最近刚刚离开了我服务了三年多的公司,因为一个无数次碰到的老问题,没钱了. 之前不知道做什么好的时候,机缘巧合之下和哒嗒网络的吴总聊了一下,发现了vr game这扇窗户,这里权当帮哒嗒网络打个广告吧.^_^ 回头看看仓惶的这一段时间,荒废了很多,抽空回来再和大家聊聊c#. 之前做了个入门系列,胡乱说了些东西.感觉入门这样子也就差不多了,该稍微提高一点了. ? 从写一段程序,到写一个app,写一个游戏,到底其中有什么不同呢?一段程序的执行时间很短,一个应用