Skip to content

cocos2d x 3.3 006 核心概念和相关类 导演

David edited this page Jan 14, 2015 · 6 revisions

Director概述

  • 单例模式
  • 继承自Ref
  • 子类DisplayLinkDirector

主要API

main Window相关

  • setOpenGLView getOpenGLView getWinSize getWinSizeInPixels getVisibleSize

Scene Management

  • runWithScene pushScene popScene popToRootScene popToSceneStackLevel replaceScene getRunningScene

游戏生命周期

  • mainLoop end pause resume drawScene isPaused stopAnimation startAnimation

opengl相关

  • setProjection getProjection setViewport setGLDefaultValues setDefaultValues setAlphaBlending setDepthTest pushMatrix popMatrix loadIdentityMatrix loadMatrix multiplyMatrix getMatrix resetMatrixStack

fps

  • getAnimationInterval setAnimationInterval isDisplayStats setDisplayStats

坐标转换

  • convertToGL convertToUI

set/get

  • getTextureCache getScheduler setScheduler getActionManager setActionManager getEventDispatcher setEventDispatcher getRenderer getConsole getDeltaTime getFrameRate

Memory Helper

  • purgeCachedData

缩放因子,屏幕适配

  • setContentScaleFactor getContentScaleFactor

导演源码查看

一些说明

  • 由于对opengl的知识只知道个大概,so相关的代码就暂略过了,重点关注下业务方面的逻辑。 这也说明cocos有多厉害,他让你不懂opengl也依然可以写流弊的游戏,这也是吸引我的地方。

源码走起

1. 单例的应用
Director* Director::getInstance()
{
    if (!s_SharedDirector)
    {
//单例
        s_SharedDirector = new (std::nothrow) DisplayLinkDirector();
        CCASSERT(s_SharedDirector, "FATAL: Not enough memory");
        s_SharedDirector->init();
    }

2. 初始化几个重要‘业务员’
bool Director::init(void)
{
    setDefaultValues();

    // scenes
    _runningScene = nullptr;
    _nextScene = nullptr;

    _notificationNode = nullptr;

    _scenesStack.reserve(15);

    // FPS
    _accumDt = 0.0f;
    _frameRate = 0.0f;
    _FPSLabel = _drawnBatchesLabel = _drawnVerticesLabel = nullptr;
    _totalFrames = 0;
    _lastUpdate = new struct timeval;

    // paused ?
    _paused = false;

    // purge ?
    _purgeDirectorInNextLoop = false;

    _winSizeInPoints = Size::ZERO;

    _openGLView = nullptr;

    _contentScaleFactor = 1.0f;

//创建调度器
    // scheduler
    _scheduler = new (std::nothrow) Scheduler();
//创建动作管理器
//并设置每一帧都调用的callback
//导致每一帧都会调用到动作管理器的update方法,进而驱动action,详见动作篇
    // action manager
    _actionManager = new (std::nothrow) ActionManager();
    _scheduler->scheduleUpdate(_actionManager, Scheduler::PRIORITY_SYSTEM, false);

//创建事件分发器
    _eventDispatcher = new (std::nothrow) EventDispatcher();

    _eventAfterDraw = new (std::nothrow) EventCustom(EVENT_AFTER_DRAW);
    _eventAfterDraw->setUserData(this);
    _eventAfterVisit = new (std::nothrow) EventCustom(EVENT_AFTER_VISIT);
    _eventAfterVisit->setUserData(this);
    _eventAfterUpdate = new (std::nothrow) EventCustom(EVENT_AFTER_UPDATE);
    _eventAfterUpdate->setUserData(this);
    _eventProjectionChanged = new (std::nothrow) EventCustom(EVENT_PROJECTION_CHANGED);
    _eventProjectionChanged->setUserData(this);


    //init TextureCache
    initTextureCache();
    initMatrixStack();

    _renderer = new (std::nothrow) Renderer;

    _console = new (std::nothrow) Console;

    return true;
}

3. 大循环, Application::run()中每一次循环调用mainloop, 程序在这里被驱动起来开始干活
void DisplayLinkDirector::mainLoop()
{
    if (_purgeDirectorInNextLoop)
    {
        _purgeDirectorInNextLoop = false;
        purgeDirector();
    }
    else if (! _invalid)
    {
//具体干事的
        drawScene();
     
//从这里看出,游戏的每一帧会清理下自动缓冲池
        // release the objects
        PoolManager::getInstance()->getCurrentPool()->clear();
    }
}

4.具体干事的, 将活儿再分发给各个业务员, 让他们怕业务去
'兄弟们,你们上'
// Draw the Scene
void Director::drawScene()
{
    // calculate "global" dt
    calculateDeltaTime();
    
    // skip one flame when _deltaTime equal to zero.
    if(_deltaTime < FLT_EPSILON)
    {
        return;
    }

    if (_openGLView)
    {
        _openGLView->pollEvents();
    }

    //tick before glClear: issue #533
    if (! _paused)
    {
//调度器update,驱动起各种update callback和各种timer的触发或cancel等
        _scheduler->update(_deltaTime);

//分发一个事件
        _eventDispatcher->dispatchEvent(_eventAfterUpdate);
    }

//opengl相关,略
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    /* to avoid flickr, nextScene MUST be here: after tick and before draw.
     * FIXME: Which bug is this one. It seems that it can't be reproduced with v0.9
     */
    if (_nextScene)
    {
        setNextScene();
    }

    pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    
    if (_runningScene)
    {
        //clear draw stats
        _renderer->clearDrawStats();
        
//当前场景的渲染
        //render the scene
        _runningScene->render(_renderer);
        
        _eventDispatcher->dispatchEvent(_eventAfterVisit);
    }

    // draw the notifications node
    if (_notificationNode)
    {
        _notificationNode->visit(_renderer, Mat4::IDENTITY, 0);
    }

    if (_displayStats)
    {
        showStats();
    }
    _renderer->render();


    _eventDispatcher->dispatchEvent(_eventAfterDraw);

    popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);

    _totalFrames++;

    // swap buffers
    if (_openGLView)
    {
        _openGLView->swapBuffers();
    }

    if (_displayStats)
    {
        calculateMPF();
    }
}

5. 再看看场景管理相关的几个函数
void Director::runWithScene(Scene *scene)
{
    CCASSERT(scene != nullptr, "This command can only be used to start the Director. There is already a scene present.");
    CCASSERT(_runningScene == nullptr, "_runningScene should be null");

    pushScene(scene);
    startAnimation();
}

void Director::replaceScene(Scene *scene)
{
    //CCASSERT(_runningScene, "Use runWithScene: instead to start the director");
    CCASSERT(scene != nullptr, "the scene should not be null");
    
    if (_runningScene == nullptr) {
        runWithScene(scene);
        return;
    }
    
    if (scene == _nextScene)
        return;
    
    if (_nextScene)
    {
        if (_nextScene->isRunning())
        {
//onExit回调
            _nextScene->onExit();
        }
        _nextScene->cleanup();
        _nextScene = nullptr;
    }

    ssize_t index = _scenesStack.size();

    _sendCleanupToScene = true;

//直接替换
    _scenesStack.replace(index - 1, scene);

    _nextScene = scene;
}

void Director::pushScene(Scene *scene)
{
    CCASSERT(scene, "the scene should not null");

    _sendCleanupToScene = false;
//栈结构
    _scenesStack.pushBack(scene);
    _nextScene = scene;
}

void Director::popScene(void)
{
    CCASSERT(_runningScene != nullptr, "running scene should not null");

//出栈
    _scenesStack.popBack();
    ssize_t c = _scenesStack.size();

    if (c == 0)
    {
        end();
    }
    else
    {
        _sendCleanupToScene = true;
        _nextScene = _scenesStack.at(c - 1);
    }
}

void Director::popToRootScene(void)
{
//直接退到root
    popToSceneStackLevel(1);
}

void Director::popToSceneStackLevel(int level)
{
    CCASSERT(_runningScene != nullptr, "A running Scene is needed");
    ssize_t c = _scenesStack.size();

    // level 0? -> end
    if (level == 0)
    {
        end();
        return;
    }

    // current level or lower -> nothing
    if (level >= c)
        return;

    auto fisrtOnStackScene = _scenesStack.back();
    if (fisrtOnStackScene == _runningScene)
    {
        _scenesStack.popBack();
        --c;
    }

//出栈直到达到需要的level
    // pop stack until reaching desired level
    while (c > level)
    {
        auto current = _scenesStack.back();

        if (current->isRunning())
        {
            current->onExit();
        }

        current->cleanup();
        _scenesStack.popBack();
        --c;
    }

    _nextScene = _scenesStack.back();

    // cleanup running scene
    _sendCleanupToScene = true;
}

小结

  • 导演的责任是重大的,功能是全面的。同时他拥有一帮厉害的业务员负责各个领域的业务,比如事件分发器,timer相关的调度器,action管理器等
  • 对场景的管理,导演维护的是一个栈结构
  • 负责opengl相关的设置,这里不懂了,略
  • 具体见上方API部分
Clone this wiki locally