原创文章,转载请注明出处:http://blog.csdn.net/sfh366958228/article/details/38845319
终于讲完了CCAction的实现原理,现在有理论基础来说场景切换的原理了,其实不难猜到很多的场景切换效果十通过CCAction来实现的。
CCDirector::sharedDirector()->replaceScene(CCTransitionRotoZoom::create(2.0f, MenuScene::scene()));这是一个基本的场景切换代码,那么就让我们从replaceScene开始看起吧~
void CCDirector::replaceScene(CCScene *pScene) { CCAssert(m_pRunningScene, "Use runWithScene: instead to start the director"); //判断是否有正在运行的场景,没有的话应以runWithScene代替replaceScene CCAssert(pScene != NULL, "the scene should not be null"); // 确保待切换场景不为空 unsigned int index = m_pobScenesStack->count(); // 获取场景栈中场景数量 m_bSendCleanupToScene = true; // 将清空场景标记为true m_pobScenesStack->replaceObjectAtIndex(index - 1, pScene); // 将场景放在容器结尾 m_pNextScene = pScene; // 将下一个场景设置为pScene }看到这时有点懵,感觉没法往下走了,寻寻觅觅,终于还是发现了结果。答案就在主循环中mainLoop,我们会调用设备的drawScene方法。
void CCDirector::drawScene(void) { calculateDeltaTime(); // 计算帧间隔时间 if (! m_bPaused) // Director是否暂停 { m_pScheduler->update(m_fDeltaTime); // 更新毁掉函数管理器 } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // OPENGL清除后台缓冲区的颜色和深度,这是每一帧OPENGL进行渲染前要做的处理。 if (m_pNextScene) { setNextScene(); // 如果有新的场景要设置,调用setNextScene函数进行相关处理。 } ... }
不难发现,关键应该在setNextScene这个方法之中。
void CCDirector::setNextScene(void) { bool runningIsTransition = dynamic_cast<CCTransitionScene*>(m_pRunningScene) != NULL; // 定义bool变量runningIsTransition,判断当前运行中的场景是否是切换场景类,如果是,将runningIsTransition设为true bool newIsTransition = dynamic_cast<CCTransitionScene*>(m_pNextScene) != NULL; // 定义bool变量newIsTransition,判断要设置的新场景是否是切换场景类,如果是,将newIsTransition设为true if (! newIsTransition) { // 如果新场景不是切换场景类而是一个普通场景 if (m_pRunningScene) { // 如果m_pRunningScene不为空,则调用对应场景结束方法 m_pRunningScene->onExitTransitionDidStart(); m_pRunningScene->onExit(); } // 如果m_bSendCleanupToScene标记为true且有正在运行的场景则调用它的cleanup函数 if (m_bSendCleanupToScene && m_pRunningScene) { m_pRunningScene->cleanup(); } } if (m_pRunningScene) { // 调用当前正在运行的场景的释放函数 m_pRunningScene->release(); } m_pRunningScene = m_pNextScene; // 将新场景置为当前场景 m_pNextScene->retain(); //新场景计数加1 m_pNextScene = NULL; // 新场景指针置为空 if ((! runningIsTransition) && m_pRunningScene) { // 调用新场景的onEnter函数 m_pRunningScene->onEnter(); m_pRunningScene->onEnterTransitionDidFinish(); } }
讲到这,我们已经大概了解了场景切换的步骤,最后的切换动作实现,还是落在了场景切换类自身的实现上。
void CCTransitionRotoZoom::onEnter() { // 调用基类的相应函数 CCTransitionScene::onEnter(); // 设置新场景的初始缩放值为0.001,缩小了100倍 m_pInScene->setScale(0.001f); // 设置原场景的初始缩放值为原大小 m_pOutScene->setScale(1.0f); // 设置场景的锚点做为旋转缩放中心 m_pInScene->setAnchorPoint(ccp(0.5f, 0.5f)); m_pOutScene->setAnchorPoint(ccp(0.5f, 0.5f)); //创建一个序列动画 CCActionInterval *rotozoom = (CCActionInterval*)(CCSequence::create(CCSpawn::create // 这个序列动画有两部分,第一部分是一个组合动画,这个组合动画由缩放和旋转组合而成 (CCScaleBy::create(m_fDuration/2, 0.001f), // 一半动画时间内从当前缩放值缩小100倍 CCRotateBy::create(m_fDuration/2, 360 * 2), // 一半动画时间内从当前旋转状态旋转两圈 NULL), CCDelayTime::create(m_fDuration/2), // 序列动画的第二部分是一个暂停一半动画时间的暂停动画 NULL)); // 对原场景运行上面创建的序列动画,让它在一半动画时长内旋转2圈,并由原大小缩小100倍,然后暂停一半动画时长 m_pOutScene->runAction(rotozoom); // 对新的场景运行另一个序列动画 m_pInScene->runAction(CCSequence::create(// 这个序列动画也有两部分构成,第一部分是上面序列动画的反向动画,第二部分是调用finish函数 rotozoom->reverse(), CCCallFunc::create(this, callfunc_selector(CCTransitionScene::finish)), NULL)); }
看到这,我们最初的想法也基本得到证明,在不过和语气有点不一样得是,replaceScene之后,场景并没有直接切换,而是等到主线程的步骤中再继续,这两天对Action和场景切换的原理进行了简单讲解,有没有对原理性的东西更加感兴趣呢?
Cocos2d-x 2.0 TestCpp之场景切换动画深入分析:http://blog.csdn.net/honghaier/article/details/8475341
原文地址:http://blog.csdn.net/sfh366958228/article/details/38848721