经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 游戏设计 » 查看文章
?Cocos2d-x 学习笔记(3.2) TransitionScene 过渡场景和场景切换的过程
来源:cnblogs  作者:深潮  时间:2019/8/19 8:35:37  对本文有异议

1. 简介

过渡场景TransitionScene直接继承了场景Scene。能够在场景切换过程中实现“过渡”效果,而不是让窗口在下一帧突然展示另一个场景。

2. create

构造函数:

  1. TransitionScene::TransitionScene()
  2. : _inScene(nullptr)
  3. , _outScene(nullptr)
  4. , _duration(0.0f)
  5. , _isInSceneOnTop(false)
  6. , _isSendCleanupToScene(false)
  7. {
  8. }

create方法有2个参数:float t, Scene *scene。调用了initWithDuration,传入这两个参数。

参数scene不能为空。

1. 成员变量时间_duration设为参数t,成员变量_inScene设为参数scene。过渡场景引用了参数场景,参数场景要retain。

2. 导演执行getRunningScene,把当前正执行的场景作为_outScene。

3. 如果当前正执行的场景为空,则调用Scene::create()创建一个空场景,空场景作为_outScene。

4. _outScene指向的场景被引用了,_outScene执行retain。

5. 执行sceneOrder(),决定inScene和outScene的绘制顺序。该方法可以被子类重写,只是设置了成员变量_isInSceneOnTop的值为true/false。

3. onEnter

场景的onEnter方法在该场景每次进入窗口时执行。

TransitionScene的子类会重写onEnter方法,重写后的方法体内会先调用父类TransitionScene的onEnter方法。

1. 首先调用父类Scene onEnter方法,实际上执行的是Scene的父类Node的onEnter方法。

2. 导演的事件分发器执行setEnabled(false),停止事件分发器的工作。

3. _outScene->onExitTransitionDidStart() 要退出的场景执行onExitTransitionDidStart。

4. _inScene->onEnter() 要出现的场景执行onEnter。

简而言之,过渡的开始时,要退出的准备退出,要出现的开始出现。

4. onExit()

场景的onExit方法在该场景每次退出窗口时执行。

1. 首先调用父类Scene onExit方法,实际上执行的是Scene的父类Node的onExit方法。

2. 导演的事件分发器执行setEnabled(true),事件分发器的可以分发事件了。

3. _outScene->onExit(); 要退出的场景执行onExit,完全退出。

4. _inScene->onEnterTransitionDidFinish() 要出现的场景执行onEnterTransitionDidFinish。

简而言之,过渡的结束时,要退出的完成退出,要进入的完成进入。此时,窗口只有我们设置的要进入的场景了。

5. draw(...)

过渡场景绘制方法的源码:

  1. void TransitionScene::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
  2. {
  3. Scene::draw(renderer, transform, flags);
  4. if( _isInSceneOnTop ) {
  5. _outScene->visit(renderer, transform, flags);
  6. _inScene->visit(renderer, transform, flags);
  7. } else {
  8. _inScene->visit(renderer, transform, flags);
  9. _outScene->visit(renderer, transform, flags);
  10. }
  11. }

可以看出,绘制根据_isInSceneOnTop决定inScene和outScene的绘制顺序。

构造函数默认false。在create方法会调用sceneOrder()设置。子类可以重写sceneOrder方法,实现TransitionScene不同子类的要进入场景和要退出场景绘制顺序的不同。

6. 子类 TransitionJumpZoom

TransitionScene是所有过渡场景的父类,每种子类都是一种有不同特效的过渡场景。

这次用子类TransitionJumpZoom为例进行学习。

该过渡场景除去构造和析构仅2个方法。该过渡场景重写了onEnter方法,说明在该方法包含了过渡特效的逻辑。

- TransitionJumpZoom::onEnter()

1. 首先执行父类TransitionScene::onEnter()。让outScene(runningScene)准备退出。

2. 设置inScene和outScene在过渡开始时的初始属性。

  1. _inScene->setScale(0.5f);
  2. _inScene->setPosition(s.width, 0);
  3. _inScene->setAnchorPoint(Vec2(0.5f, 0.5f));
  4. _outScene->setAnchorPoint(Vec2(0.5f, 0.5f));

3.创建3个动作。有跳跃和缩放

  1. ActionInterval *jump = JumpBy::create(_duration/4, Vec2(-s.width,0), s.width/4, 2);
  2. ActionInterval *scaleIn = ScaleTo::create(_duration/4, 1.0f);
  3. ActionInterval *scaleOut = ScaleTo::create(_duration/4, 0.5f);

4. 创建两个动作队列。

  1. auto jumpZoomOut = Sequence::create(scaleOut, jump, nullptr);
  2. auto jumpZoomIn = Sequence::create(jump, scaleIn, nullptr);

5. 两个场景runAction。

  1. ActionInterval *delay = DelayTime::create(_duration/2);
  2. _outScene->runAction(jumpZoomOut);
  3. _inScene->runAction
  4. (
  5. Sequence::create
  6. (
  7. delay,
  8. jumpZoomIn,
  9. CallFunc::create(CC_CALLBACK_0(TransitionScene::finish,this)),
  10. nullptr
  11. )
  12. );

在要进入的场景的动作序列结束前,执行父类的TransitionScene::finish。

- TransitionScene finish

简要的说,是设置inScene和outScene的属性。从而对屏幕的窗口而言,过渡的特效执行完成,inScene可见,outScene不可见,两场景的位置、旋转、缩放都设为了默认值。

在属性设置之后,执行:

  1. this->schedule(CC_SCHEDULE_SELECTOR(TransitionScene::setNewScene), 0);

该语句建了一个Timer,时间间隔为0,说明下一帧就要执行参数回调函数setNewScene。

- TransitionScene setNewScene

1. 首先unschedule了上一帧的Timer。

2. 把导演属性_sendCleanupToScene赋给TransitionScene属性_isSendCleanupToScene。

3. 执行导演的replaceScene(_inScene),将inScene作为了导演的nextScene。

4. 最后outScene可见。

7. 场景切换的运行过程

这里用replaceScene为例。

例子中,我们点击菜单项,触发replaceScene函数,参数是某个过渡场景。

过渡场景的开始 到onEnter()

1. 本帧的GLView接收到触摸事件(鼠标点击菜单项),触发了回调函数,回调函数中新建了一个新场景和过渡场景,过渡场景的inScene为执行导演的replaceScene,参数为新场景。

2. replaceScene中:导演_sendCleanupToScene置true,新场景入栈,新场景成为nextScene。nextScene原本为NULL。

3. 本帧结束。进入下一帧。

4. 下一帧在scheduler update之后判断到存在nextScene,执行setNextScene方法。

5. setNextScene:

  1. void Director::setNextScene()
  2. {
  3. _eventDispatcher->dispatchEvent(_beforeSetNextScene);
  4. bool runningIsTransition = dynamic_cast<TransitionScene*>(_runningScene) != nullptr; // false
  5. bool newIsTransition = dynamic_cast<TransitionScene*>(_nextScene) != nullptr; // true
  6.  
  7. if (! newIsTransition) //新场景是过渡场景,不执行
  8. {
  9. if (_runningScene)
  10. {
  11. _runningScene->onExitTransitionDidStart();
  12. _runningScene->onExit();
  13. }
  14. // issue #709. the root node (scene) should receive the cleanup message too
  15. // otherwise it might be leaked.
  16. if (_sendCleanupToScene && _runningScene)
  17. {
  18. _runningScene->cleanup();
  19. }
  20. }
  21. if (_runningScene)
  22. {
  23. _runningScene->release();
  24. }
  25. _runningScene = _nextScene;
  26. _nextScene->retain();
  27. _nextScene = nullptr; //nextScene至此成为了runningScene
  28.  
  29. if ((! runningIsTransition) && _runningScene) //曾经的runningscene为false,执行
  30. {
  31. _runningScene->onEnter(); //过渡场景的onEnter
  32. _runningScene->onEnterTransitionDidFinish();
  33. }
  34. _eventDispatcher->dispatchEvent(_afterSetNextScene);
  35. }

6. 执行过渡场景的onEnter:

  1. 执行Node onEnter。

  2. 执行TransitionScene onEnter,导演的eventDispatcher停用,要退出的场景onExitTransitionDidStart,要进入的场景onEnter。

  3. 为inScene和outScene分别创建动作序列。分别runAction。

过渡场景的结束 到onExit()

1. 过渡场景中,新场景动作序列最后一个动作是回调动作CallFunc,调用TransitionScene finish(),在设置属性之后,在下一帧通过Scheduler调用setNewScene方法。

2. setNewScene中:replaceScene(inScene),实现了nextScene指向新场景。此时,runningScene是过渡场景。

3. 在下下一帧会执行导演setNextScene,因为runningScene和nextScene都存在,runningScene过渡场景执行onExitTransitionDidStart onExit。

  1. bool runningIsTransition = dynamic_cast<TransitionScene*>(_runningScene) != nullptr; // true
  2. bool newIsTransition = dynamic_cast<TransitionScene*>(_nextScene) != nullptr; //false
  3.  
  4. if (! newIsTransition) //执行
  5. {
  6. if (_runningScene) //过渡场景onExit
  7. {
  8. _runningScene->onExitTransitionDidStart();
  9. _runningScene->onExit();
  10. }
  11. if (_sendCleanupToScene && _runningScene)
  12. {
  13. _runningScene->cleanup();
  14. }
  15. }
  16. //......

过渡场景的onExit中,要退出的场景执行onExit,完全退出,要出现的场景执行onEnterTransitionDidFinish,完全进入。同时,导演的eventDispatcher启用。

cleanup()

继续setNextScene,_sendCleanupToScene在replaceScene时置true,过渡场景执行TransitionScene cleanup()。

  1. Scene::cleanup();
  2. if( _isSendCleanupToScene )
  3. _outScene->cleanup();

调用了Node cleanup()。_isSendCleanupToScene由导演_sendCleanupToScene设置,为true时,对要退出的场景cleanup()。

_sendCleanupToScene

在导演replaceScene时置true,导演pushScene置false,导演popScene置true。

为true时,在导演setNextScene时,对导演的runningScene cleanup(),然后runningScene被nextScene替代。

如果此时runnningScene是过渡场景,过渡场景的cleanup()除了对自己cleanup,还要通过_isSendCleanupToScene判断是否对要退出的场景cleanup。

_isSendCleanupToScene是在过渡场景动作结束时,导演_sendCleanupToScene直接赋值。

所以,导演用过渡场景作为replaceScene参数时,过渡场景和要退出的场景都会被cleanup。

原文链接:http://www.cnblogs.com/deepcho/p/cocos2dx-transitionscene.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号