zoukankan      html  css  js  c++  java
  • 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
    ", 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游戏主循环的文章能帮到你。

  • 相关阅读:
    前缀和与差分
    可行!解决bitmap缩放失真问题
    Android 中的 File renameTo() 使用
    XMPP 中客户端断线及网络异常处理
    webview 离线缓存,html5游戏适用
    Mac os x下配置 Android ndk 开发环境
    从外企到国企的工作环境改变
    微软SQL Server数据库SQL语句导入导出大全,包括与其他数据库和文件的数据的导入导出
    人生第一职业:我当了人民教师
    JOIN 分为内连接,外连接(左外连接,右外连接,全外连接)
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4073651.html
Copyright © 2011-2022 走看看