Cocos2d-x Scene笔记

1.create

Scene* Scene::create()
{
    Scene *ret = new (std::nothrow) Scene();
    if (ret && ret->init())
    {
        ret->autorelease();
        return ret;
    }
    else
    {
        CC_SAFE_DELETE(ret);
        return nullptr;
    }
}
Scene::Scene()
{
    // only full screen node ingnore anchor point
    _ignoreAnchorPointForPosition = true;
    // anchor point in center of screen
    setAnchorPoint(Vec2(0.5f, 0.5f));
    // camera need sort
    _cameraOrderDirty = true;

    // create default camera, all node see by default camera
    // will create a perspective camera
    _defaultCamera = Camera::create();
    // camera also need draw background or not
    addChild(_defaultCamera);

    _event = Director::getInstance()->getEventDispatcher()->addCustomEventListener(Director::EVENT_PROJECTION_CHANGED, std::bind(&Scene::onProjectionChanged, this, std::placeholders::_1));
    _event->retain();

    Camera::_visitingCamera = nullptr;
}
bool Scene::init()
{
    auto size = Director::getInstance()->getWinSize();
    // use window size to set scene's content size, so scene is full screen default
    return initWithSize(size);
}
bool Scene::initWithSize(const Size& size)
{
    setContentSize(size);
    return true;
}

2.render

void Scene::render(Renderer* renderer, const Mat4& eyeTransform, const Mat4* eyeProjection)
{
    auto director = Director::getInstance();
    Camera* defaultCamera = nullptr;
    // get transform matrix use for transform children(parents's transform will affact children
    // position), that's if you translate scene, all node in the scene will translate with scene
    // this function will call  one more times by visit()'s processParentFlags()
    // but this function will not transform one more time, because _transformDirty turn false 
    const auto& transform = getNodeToParentTransform();

    for (const auto& camera : getCameras())
    {
        if (!camera->isVisible())
            continue;

        Camera::_visitingCamera = camera;
        if (Camera::_visitingCamera->getCameraFlag() == CameraFlag::DEFAULT)
        {
            defaultCamera = Camera::_visitingCamera;
        }

        // There are two ways to modify the "default camera" with the eye Transform:
        // a) modify the "nodeToParentTransform" matrix
        // b) modify the "additional transform" matrix
        // both alternatives are correct, if the user manually modifies the camera with a camera->setPosition()
        // then the "nodeToParent transform" will be lost.
        // And it is important that the change is "permanent", because the matrix might be used for calculate
        // culling and other stuff.
        if (eyeProjection)
            camera->setAdditionalProjection(*eyeProjection * camera->getProjectionMatrix().getInversed());
        camera->setAdditionalTransform(eyeTransform.getInversed());

        director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
        director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, Camera::_visitingCamera->getViewProjectionMatrix());
        // apply viewport
        camera->apply();
        //clear background with max depth
        camera->clearBackground();
        //visit the scene
        visit(renderer, transform, 0);
        // render scene
        renderer->render();
        camera->restore();

        director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);

        // we shouldn't restore the transform matrix since it could be used
        // from "update" or other parts of the game to calculate culling or something else.
        // camera->setNodeToParentTransform(eyeCopy);
    }
    Camera::_visitingCamera = nullptr;
}

3.visit

void Node::visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t parentFlags)
{
    // quick return if not visible. children won't be drawn.
    if (!_visible)
    {
        return;
    }
    // if scene get to this, it will only process flag, not transform _modelViewTransform
    // even though it will get into "_modelViewTransform = this->transform(parentTransform)"
    // it return quick, get flags = FLAGS_DIRTY_MASK = 3
    uint32_t flags = processParentFlags(parentTransform, parentFlags);

    // IMPORTANT:
    // To ease the migration to v3.0, we still support the Mat4 stack,
    // but it is deprecated and your code should not rely on it
    _director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    _director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);

    bool visibleByCamera = isVisitableByVisitingCamera();

    int i = 0;

    if(!_children.empty())
    {
        sortAllChildren();
        // draw children zOrder < 0
        // draw left hand node
        for( ; i < _children.size(); i++ )
        {
            auto node = _children.at(i);

            if (node && node->_localZOrder < 0)
                node->visit(renderer, _modelViewTransform, flags);
            else
                break;
        }
        // self draw
        // draw centre node
        // if scene get to this, draw will do nothing
        if (visibleByCamera)
            this->draw(renderer, _modelViewTransform, flags);
        // draw right hand node
        for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
            (*it)->visit(renderer, _modelViewTransform, flags);
    }
    else if (visibleByCamera)
    {
        this->draw(renderer, _modelViewTransform, flags);
    }

    _director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}
uint32_t Node::processParentFlags(const Mat4& parentTransform, uint32_t parentFlags)
{
    // Fixes Github issue #16100. Basically when having two cameras, one camera might set as dirty the
    // node that is not visited by it, and might affect certain calculations. Besides, it is faster to do this.
    if (!isVisitableByVisitingCamera())
        return parentFlags;

    uint32_t flags = parentFlags;
    flags |= (_transformUpdated ? FLAGS_TRANSFORM_DIRTY : 0);
    flags |= (_contentSizeDirty ? FLAGS_CONTENT_SIZE_DIRTY : 0);


    if(flags & FLAGS_DIRTY_MASK)
        // transform this node by parent's transform
        _modelViewTransform = this->transform(parentTransform);

    _transformUpdated = false;
    _contentSizeDirty = false;

    return flags;
}
Mat4 Node::transform(const Mat4& parentTransform)
{
    // get self transform and multiply with parent's transform
    return parentTransform * this->getNodeToParentTransform();
}

4.draw

// scene draw will do nothing
void Node::draw(Renderer* renderer, const Mat4 &transform, uint32_t flags)
{
}

5.run

auto scene = HelloWorld::scene();
// this use only when director first run a scene
// if not, please use replaceScene()
director->runWithScene(scene);
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::pushScene(Scene *scene)
{
    CCASSERT(scene, "the scene should not null");

    _sendCleanupToScene = false;
    // push this scene to the scenes stack
    _scenesStack.pushBack(scene);
    // set this scene to be next scene, and will repalce running scene
    // before replace running scene, must setup new scene first, and then
    // delete running scene, and run new scene 
    _nextScene = scene;
}
// init data before first run mainloop
void DisplayLinkDirector::startAnimation()
{
    // get last update time
    _lastUpdate = std::chrono::steady_clock::now();

    // 将场景不可运行标志_invalid改为false表示可以进入主循环
    _invalid = false;

    _cocos2d_thread_id = std::this_thread::get_id();

    Application::getInstance()->setAnimationInterval(_animationInterval);

    // fix issue #3509, skip one fps to avoid incorrect time calculation.
    // 将会跳过一次calculateDeltaTime()函数执行,并且把_deltaTime清零
    setNextDeltaTimeZero(true);
}
// after set run scene, get to mainloop
void DisplayLinkDirector::mainLoop()
{
    if (_purgeDirectorInNextLoop)
    {
        _purgeDirectorInNextLoop = false;
        purgeDirector();
    }
    else if (_restartDirectorInNextLoop)
    {
        _restartDirectorInNextLoop = false;
        restartDirector();
    }
    else if (! _invalid)
    {
        //
        drawScene();

        // release the objects
        PoolManager::getInstance()->getCurrentPool()->clear();
    }
}
// Draw the Scene
void Director::drawScene()
{
    // calculate "global" dt
    calculateDeltaTime();

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

    if (! _paused)
    {
        _eventDispatcher->dispatchEvent(_eventBeforeUpdate);
        _scheduler->update(_deltaTime);
        _eventDispatcher->dispatchEvent(_eventAfterUpdate);
    }

    _renderer->clear();
    experimental::FrameBuffer::clearAllFBOs();
    // we have set the first scene to _nextScene
    // so will get to setNextScene() and set first scene to _runningScene
    // and set _nextScene to nullptr, and before we set a second scene the
    // first scene will always get render, and setNextScene() will not run again
    if (_nextScene)
    {
        setNextScene();
    }

    pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    // if you not set a next scene this _runningScene will always get render
    if (_runningScene)
    {
        //clear draw stats
        _renderer->clearDrawStats();

        //render the scene
        _openGLView->renderScene(_runningScene, _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();
    }
}
void Director::setNextScene()
{
    // if first run a scene, _runningScene = nullptr, 
    // runningIsTransition = false, first scene will get into onEnter()
    bool runningIsTransition = dynamic_cast<TransitionScene*>(_runningScene) != nullptr;
    // if first run a scene, _nextScene = first scene, newIsTransition = false
    // _runningScene will not get into onExit(), becuse _runningScene = nullptr
    bool newIsTransition = dynamic_cast<TransitionScene*>(_nextScene) != nullptr;

    // If it is not a transition, call onExit/cleanup
     if (! newIsTransition)
     {
         // before get into next scene, current scene will do cleanup and onExit()
         if (_runningScene)
         {
             _runningScene->onExitTransitionDidStart();
             _runningScene->onExit();
         }

         if (_sendCleanupToScene && _runningScene)
         {
             _runningScene->cleanup();
         }
     }
    // 
    if (_runningScene)
    {
        _runningScene->release();
    }
    // replace running scene
    _runningScene = _nextScene;
    _nextScene->retain();
    _nextScene = nullptr;
    // if new scene is not a transition scene, call onEnter() because it is a new scene
    if ((! runningIsTransition) && _runningScene)
    {
        _runningScene->onEnter();
        _runningScene->onEnterTransitionDidFinish();
    }
}

6.replace

void Director::replaceScene(Scene *scene)
{
    //CCASSERT(_runningScene, "Use runWithScene: instead to start the director");
    CCASSERT(scene != nullptr, "the scene should not be null");
    // if this scene is the first scene, start with runWithScene(scene) not replaceScene(Scene *scene)
    if (_runningScene == nullptr) {
        runWithScene(scene);
        return;
    }
    // if _nextScene == scene, maybe you have replace scene but you call replace again
    if (scene == _nextScene)
        return;
    // you have push one scene to scene stack, and then you call replace scene
    if (_nextScene)
    {
        // impossible
        if (_nextScene->isRunning())
        {
            _nextScene->onExit();
        }
        // cleanup current one and set a new one
        _nextScene->cleanup();
        _nextScene = nullptr;
    }

    ssize_t index = _scenesStack.size() - 1;

    _sendCleanupToScene = true;
    _scenesStack.replace(index, scene);
    // set this new scene to be next scene
    _nextScene = scene;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值