Cocos2dx运行的流程

Why?

做什么事情都要问下自己为什么,带着目的去做,才好抓住重点。
  为什么要了解Cocos的运行流程呢?没有深入的理解cocos就去开发,这个是能接受的,因为人生不是炒菜,不能等什么都准备好了才下锅。但是在开发了一段时间以后是不是想对cocos的运行机制有一定了解呢。我建议大家要适度的刨根问底,什么叫适度呢?比如现在计算机发展那么多年了,你想了解程序是怎么运行的,你要去学习操作系统、计算机组成原理、逻辑门电路。如果没有基础的人学这些至少要个几年时间,这个就是不适度。但是我们经常用的cocos,我们要去刨根问底要了解什么呢,比如启动流程、绘制流程、结束流程、以及和各个平台的交互等,底层的OpenGL ES我们都可以不用去了解,除非要在绘图方面有深入的研究。

游戏基本运行流程

本人刚进公司做的是嵌入式平台的游戏开发,用C语言开发,我以前也没做过游戏开发,刚开始就是添加了图片或者帧动画到场景中显示,当时我很困惑,是怎么显示出来的呢。后来我就去研究了底层的代码,终于了解了游戏的基本运行原理。一图胜千文,先上图:


未命名文件.png

粗略代码如下:

int main()
{
    initGame();
    while(bRun)
    {
        processLogic();    // 处理逻辑,该函数中会处理游戏中元素的各种属性变化
        drawScene();        // 根据游戏中的元素的各种属性进行绘图,比如位置 透明度 缩放等
        sleep(1000/8);        // 睡眠一段时间 此处为1/8秒,即一秒8帧, 此处是比较粗略的处理方法,没有考虑到逻辑处理和绘图的用时
    }
    return 0;
}

可以看出,游戏的运行流程就是一个死循环,一直不停的处理逻辑并且绘制界面。直到满足某个条件退出这个死循环则游戏结束。
对照这个流程,我们要去看一下cocos中的这个流程是怎么走的。

游戏引擎版本:3.15

Windows平台

入口:project/proj.win32/main.cpp

int WINAPI _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函数中查看:

int Application::run()
{
    ...
    ...
    // Initialize instance and cocos2d.
    if (!applicationDidFinishLaunching())   // AppDelegate中回调
    {
        return 1;
    }


    while(!glview->windowShouldClose())     // 死循环
    {
        QueryPerformanceCounter(&nNow);
        interval = nNow.QuadPart - nLast.QuadPart;
        if (interval >= _animationInterval.QuadPart)
        {
            nLast.QuadPart = nNow.QuadPart;
            director->mainLoop();           // 逻辑处理和绘图
            glview->pollEvents();
        }
        else
        {
            waitMS = (_animationInterval.QuadPart - interval) * 1000LL / freq.QuadPart - 1L;
            if (waitMS > 1L)
                Sleep(waitMS);              // 等待下一帧
        }
    }
    
    ...
    ...

    return 0;
}

是不是和上方的流程一致?(这里只贴了关键代码)。
我们再进入Director的mainLoop函数中查看详细信息。

void Director::mainLoop()
{
    if (_purgeDirectorInNextLoop)
    {
        _purgeDirectorInNextLoop = false;
        purgeDirector();
    }
    else if (_restartDirectorInNextLoop)
    {
        _restartDirectorInNextLoop = false;
        restartDirector();
    }
    else if (! _invalid)
    {
        drawScene();            // 处理逻辑和绘图
     
        // release the objects
        PoolManager::getInstance()->getCurrentPool()->clear();      // 自动释放池 后面会讲
    }
}

再看看drawScene中的逻辑

void Director::drawScene()
{
    // 此处会调用各个节点中的update,就是我们经常处理逻辑的地方
    if (! _paused)
    {
        _eventDispatcher->dispatchEvent(_eventBeforeUpdate);
        _scheduler->update(_deltaTime);
        _eventDispatcher->dispatchEvent(_eventAfterUpdate);
    }

    ...
    ...
    
    if (_runningScene)
    {
#if (CC_USE_PHYSICS || (CC_USE_3D_PHYSICS && CC_ENABLE_BULLET_INTEGRATION) || CC_USE_NAVMESH)
        _runningScene->stepPhysicsAndNavigation(_deltaTime);
#endif
        //clear draw stats
        _renderer->clearDrawStats();
        
        //render the scene
        _openGLView->renderScene(_runningScene, _renderer);     // 绘图  绘制过程后面说
        
        _eventDispatcher->dispatchEvent(_eventAfterVisit);
    }

    ...
    ...
}

里面先处理了逻辑,然后绘制的界面。与基本的游戏流程一致。

android平台

看完Windows端,我们来看android端。

1:加载so库

cocos2d\cocos\platform\android\java\src\org\cocos2dx\lib\Cocos2dxActivity.java中在onCreate中调用的onLoadNativeLibraries方法

protected void onLoadNativeLibraries() {
        try {
            ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
            Bundle bundle = ai.metaData;
            String libName = bundle.getString("android.app.lib_name");
            System.loadLibrary(libName);
        } catch (Exception e) {
            e.printStackTrace();
        }
  }

现在的so的名称要在Manifest中配置,了解了这个设定后我们后面可以更改这些配置。

2:初始化SurfaceView

surfaceView是安卓中的一种view,是开线程进行绘制的,不会影响主线程的绘制。所以本质上就是一个死循环在跑。

3:添加renderer

this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());

4:renderer的初始化

@Override
    public void onSurfaceCreated(final GL10 GL10, final EGLConfig EGLConfig) {
        Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight);
        this.mLastTickInNanoSeconds = System.nanoTime();
        mNativeInitCompleted = true;
    }

调用了一个nativeInit,我们来找找这个调用了哪个Jni
在cocos2d\cocos\platform\android\javaactivity-android.cpp中我们找到另外Jni调用的地方(关于jni的调用后面会说)

JNIEXPORT void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv*  env, jobject thiz, jint w, jint h)
{
    auto director = cocos2d::Director::getInstance();
    auto glview = director->getOpenGLView();
    if (!glview)
    {
        glview = cocos2d::GLViewImpl::create("Android app");
        glview->setFrameSize(w, h);
        director->setOpenGLView(glview);

        cocos2d::Application::getInstance()->run();
    }
    else
    {
        cocos2d::GL::invalidateStateCache();
        cocos2d::GLProgramCache::getInstance()->reloadDefaultGLPrograms();
        cocos2d::DrawPrimitives::init();
        cocos2d::VolatileTextureMgr::reloadAllTextures();

        cocos2d::EventCustom recreatedEvent(EVENT_RENDERER_RECREATED);
        director->getEventDispatcher()->dispatchEvent(&recreatedEvent);
        director->setGLDefaultValues();
    }
    cocos2d::network::_preloadJavaDownloaderClass();
}

看到了没有,里面又有Application中的run函数调用,跟进到run函数中查看
大家注意,每个平台的Application文件是不一样的,这个后面会说到

int Application::run()
{
    // Initialize instance and cocos2d.
    if (! applicationDidFinishLaunching())
    {
        return 0;
    }

    return -1;
}

发现这个run跟windows下面的run是不一样的,那么在哪里绘图呢?我们回头再看看那个renderer

5:renderer绘制

@Override
    public void onDrawFrame(final GL10 gl) {
        /*
         * No need to use algorithm in default(60 FPS) situation,
         * since onDrawFrame() was called by system 60 times per second by default.
         */
        if (Cocos2dxRenderer.sAnimationInterval <= 1.0 / 60 * Cocos2dxRenderer.NANOSECONDSPERSECOND) {
            Cocos2dxRenderer.nativeRender();
        } else {
            final long now = System.nanoTime();
            final long interval = now - this.mLastTickInNanoSeconds;
        
            if (interval < Cocos2dxRenderer.sAnimationInterval) {
                try {
                    Thread.sleep((Cocos2dxRenderer.sAnimationInterval - interval) / Cocos2dxRenderer.NANOSECONDSPERMICROSECOND);
                } catch (final Exception e) {
                }
            }
            /*
             * Render time MUST be counted in, or the FPS will slower than appointed.
            */
            this.mLastTickInNanoSeconds = System.nanoTime();
            Cocos2dxRenderer.nativeRender();
        }
    }

在这个绘制函数中我们看到了Cocos2dxRenderer.nativeRender()这个函数的调用,找找调用的哪个jni
cocos2d\cocos\platform\android\jni\Java_org_cocos2dx_lib_Cocos2dxRenderer.cpp

JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeRender(JNIEnv* env) {
        cocos2d::Director::getInstance()->mainLoop();
    }

是不是看到了熟悉的mainLoop函数。

至此,wnidows和android平台cocos的运行流程已经理清楚了。ios平台不熟悉,不做表述。

总结

万变不离其宗,了解了基本流程以后,就可以迅速找到重点,而不会纠结每一行代码是干什么的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容