• cocos2d-x学习日志(18) --程序是怎样開始执行与结束?


    问题的由来


          怎么样使用 Cocos2d-x 高速开发游戏。方法非常easy,你能够看看其自带的例程,或者从网上搜索教程,执行起第一个HelloWorld,然后在 HelloWorld 里面写相关逻辑代码。加入我们的层、精灵等 ~ 我们并不一定须要知道 Cocos2d-x 是怎样执行或者在各种平台之上执行,也不用知道 Cocos2d-x 的游戏是怎样执行起来的。它又是怎样渲染界面的 ~~~

    两个入口


          程序入口的概念是相对的,AppDelegate 作为跨平台程序入口,在这之上做了还有一层的封装,封装了不同平台的不同实现。比方我们通常觉得一个程序是由 main 函数開始执行,那我们就去找寻。我们看到了在proj.win32文件夹下存在 main.cpp 文件,这就是我们要看的内容,例如以下:

    int APIENTRY _tWinMain(HINSTANCE hInstance,
                           HINSTANCE hPrevInstance,
                           LPTSTR    lpCmdLine,
                           int       nCmdShow)
    {
        UNREFERENCED_PARAMETER(hPrevInstance);
        UNREFERENCED_PARAMETER(lpCmdLine);
    
    #ifdef USE_WIN32_CONSOLE
        AllocConsole();
        freopen("CONIN$", "r", stdin);
        freopen("CONOUT$", "w", stdout);
        freopen("CONOUT$", "w", stderr);
    #endif
    
        // create the application instance
        AppDelegate app;
        CCEGLView* eglView = CCEGLView::sharedOpenGLView();
        eglView->setViewName("HelloLua");
        eglView->setFrameSize(480, 320);
        int ret = CCApplication::sharedApplication()->run();
    
    #ifdef USE_WIN32_CONSOLE
        FreeConsole();
    #endif
    
        return ret;
    }


    在这里我们看见了程序的真正入口,包括一个 main 函数。从此进入。执行 cocos2d-x 程序。



    Android:

    我们找到 Android 平台与上面 等价 的入口点,proj.androidjnihelloluamain.cpp

    void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv*  env, jobject thiz, jint w, jint h)
    {
        if (!CCDirector::sharedDirector()->getOpenGLView())
        {
            CCEGLView *view = CCEGLView::sharedOpenGLView();
            view->setFrameSize(w, h);
    
            AppDelegate *pAppDelegate = new AppDelegate();
            CCApplication::sharedApplication()->run();
        }
        else
        {
            ccGLInvalidateStateCache();
            CCShaderCache::sharedShaderCache()->reloadDefaultShaders();
            ccDrawInit();
            CCTextureCache::reloadAllTextures();
            CCNotificationCenter::sharedNotificationCenter()->postNotification(EVENT_COME_TO_FOREGROUND, NULL);
            CCDirector::sharedDirector()->setGLDefaultValues(); 
        }
    }

          我们并没有看到所谓的 main 函数,这是因为不同的平台封装所以有着不同的实现,在 Android 平台,默认是使用 Java 开发,能够使用 Java 通过 Jni 调用 C++ 程序。而这里也正式如此。

    我们暂且仅仅需知道。由 Android 启动一个应用,通过各种峰回路转,终于执行到了Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit 函数。由此,变開始了我们 cocos2d-x Android 平台的程序入口处。对于跨平台的 cocos2d-x 来说,除非必要,否则可不必深究其理,比方想要使用 Android 平台固有的特性等,那就须要很多其它的了解 Jni 用法,以及 Android 操作系统的很多其它细节。


    程序的流程 (这里以 Win32的实现为主。其它平台触类旁通就可以)



    凝视:

          我们从 main.cpp 中 CCApplication::sharedApplication()–>run(); 这一句看起。这一句标志着, cocos2d-x 程序正式開始执行。一点点開始分析,我们定位到 sharedApplication() 方法的实现。

    CCApplication.cpp:

    int CCApplication::run()
    {
        PVRFrameEnableControlWindow(false);
    
        // Main message loop:
        MSG msg;
        LARGE_INTEGER nFreq;
        LARGE_INTEGER nLast;
        LARGE_INTEGER nNow;
    
        QueryPerformanceFrequency(&nFreq);
        QueryPerformanceCounter(&nLast);
    
        // Initialize instance and cocos2d.
        if (!applicationDidFinishLaunching())
        {
            return 0;
        }
    
        CCEGLView* pMainWnd = CCEGLView::sharedOpenGLView();
        pMainWnd->centerWindow();
        ShowWindow(pMainWnd->getHWnd(), SW_SHOW);
    
        while (1)
        {
            if (! PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
            {
                // Get current time tick.
                QueryPerformanceCounter(&nNow);
    
                // If it's the time to draw next frame, draw it, else sleep a while.
                if (nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart)
                {
                    nLast.QuadPart = nNow.QuadPart;
                    CCDirector::sharedDirector()->mainLoop();
                }
                else
                {
                    Sleep(0);
                }
                continue;
            }
    
            if (WM_QUIT == msg.message)
            {
                // Quit message loop.
                break;
            }
    
            // Deal with windows message.
            if (! m_hAccelTable || ! TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    
        return (int) msg.wParam;
    }
    
    void CCApplication::setAnimationInterval(double interval)
    {
        LARGE_INTEGER nFreq;
        QueryPerformanceFrequency(&nFreq);
        m_nAnimationInterval.QuadPart = (LONGLONG)(interval * nFreq.QuadPart);
    }
    
    //////////////////////////////////////////////////////////////////////////
    // static member function
    //////////////////////////////////////////////////////////////////////////
    CCApplication* CCApplication::sharedApplication()
    {
        CC_ASSERT(sm_pSharedApplication);
        return sm_pSharedApplication;
    }

          从 sharedApplication() 方法,到 run() 方法。在这之前,我们须要调用到它的构造函数,否则不能执行。这就是为什么在 CCApplication::sharedApplication()–>run(); 

    之前,我们首先使用了 AppDelegate app; 创建 AppDelegate 变量的原因!

          AppDelegate 和 CCAppliation 是什么关系! 

          由 AppDelegate 的定义我们能够知道,它是 CCApplication 子类,在创建子类对象的时候,调用其构造函数的同一时候。父类构造函数也会执行,然后就将 AppDelegate 的对象赋给了 CCApplication 的静态变量,而在 AppDelegate 之中我们实现了applicationDidFinishLaunching 方法,所以在 CCApplication 中 run 方法的開始处调用的就是 AppDelegate 之中的实现。而我们在此方法中我们初始化了一些变量,创建了第一个 CCScene 场景等。之后的控制权,便全权交给了 CCDirector::sharedDirector()–>mainLoop(); 方法了。


    从 CCApplication 到 CCDirector

          cocos2d-x 程序已经执行起来了。我们继续下一步,mainLoop 函数:
    CCDirector* CCDirector::sharedDirector(void)
    {
        if (!s_SharedDirector)
        {
            s_SharedDirector = new CCDisplayLinkDirector();
            s_SharedDirector->init();
        }
    
        return s_SharedDirector;
    }
    
    void CCDisplayLinkDirector::mainLoop(void)
    {
        if (m_bPurgeDirecotorInNextLoop)
        {
            m_bPurgeDirecotorInNextLoop = false;
            purgeDirector();
        }
        else if (! m_bInvalid)
         {
             drawScene();
         
             // release the objects
             CCPoolManager::sharedPoolManager()->pop();        
         }
    }
          游戏的执行以场景为基础。每时每刻都有一个场景正在执行,其内部有一个场景栈,遵循后进后出的原则,当我们显示的调用 end() 方法,或者弹出当前场景之时,其自己主动推断,假设没有场景存在,也会触发 end() 方法,以说明场景执行的结束,而游戏假设没有场景,就像演出没有了舞台,程序进入最后收尾的工作,通过改动变量 m_bPurgeDirecotorInNextLoop 促使在程序 mainLoop 方法之内调用 purgeDirector方法。



          走到最后一步,看 CCEGLView 是假设负责收尾工作的:
    void CCEGLView::end()
    {
        if (m_hWnd)
        {
    #if(_MSC_VER >= 1600)
            if(m_bSupportTouch)
    		{
    		    s_pfUnregisterTouchWindowFunction(m_hWnd);
    		}
    #endif /* #if(_MSC_VER >= 1600) */
            DestroyWindow(m_hWnd);
            m_hWnd = NULL;
        }
        s_pMainWindow = NULL;
        UnregisterClass(kWindowClassName, GetModuleHandle(NULL));
        delete this;
    }

          end() 方法非常easy,仅仅须要看到最后一句 delete this; 就明确了。

    參考博文:http://blog.leafsoar.com/archives/2013/05-05.html
  • 相关阅读:
    如何选择自动化测试框架
    Android Crash 定位
    Tomcat 高性能实现关键点
    测试用例 自动生成工具PICT与AllPairs
    《活出生命的意义》节选
    java设计模式-Iterator
    java设计模式-State模式
    java设计模式-Command模式
    java设计模式-桥接模式
    小橘灯
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/7278920.html
Copyright © 2020-2023  润新知