首页 > 学院 > 开发设计 > 正文

Cocos2d-x Scene笔记

2019-11-07 23:02:05
字体:
来源:转载
供稿:网友

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 nothingvoid 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 mainloopvoid 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 mainloopvoid 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 Scenevoid 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;}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表