• 通过onExit()实现游戏场景的暂停


      游戏暂停是一个简单的功能,但只有在实际项目中才会用到。因此学了这么久,才在这里遇到了困难。书本中并未讲解,在网上查阅资料,得到了三点解决方案:

      1.使用Director的pause方法;

      2.先保存屏幕截图,然后push另外一个场景,该场景背景就是此截图。使用RenderTexture动态纹理类保存截图;

      3.遍历节点,调用其onExit()接口。

      先说下前两个解决方案。第一个不知道为什么,启用的时候会出现卡顿,不是我想要的暂停效果。第二个方案,要多写一个暂停场景类,对于游戏体验需求比较大的游戏,自然是必不可少了,但是不适合普通的按钮暂停方式。

      这里我总结第三个方案,那就是使用onExit。根据官方文档,一个Node调用onExit接口,就是在它“退出舞台”时候调用。这个解释实在是很不具体,退出舞台时到底是做了什么?只好查看源代码了。在Node的onExit方法里面,有两个很重要的代码:

    this->pause();
    for( const auto &child: _children)
            child->onExit();

      可以看到,一个节点onExit后,其子节点也全部onExit,而且它还调用了一个pause方法,那么pause方法又做了什么呢?看代码:

    void Node::pause()
    {
        _scheduler->pauseTarget(this);
        _actionManager->pauseTarget(this);
        _eventDispatcher->pauseEventListenersForTarget(this);
    }

      1.暂停了该节点的schedule;2.暂停了该节点的动作;3.暂停了该节点的事件监听。

      也就是说,除了渲染,其余的所有动态功能几乎全都暂停了。现在就很清楚了:onExit的本质是一个回调函数,是节点在退出舞台时候调用的,功能是让它的节点“收工”。虽然它是一个回调函数,但完全可以手动调用。

      回到问题:如何让游戏场景暂停?

      场景中的主Layer是一个Node,只要主Layer调用了onExit,其所有子节点也会暂停不动了。但是,我们总有一些节点需要“加班”,比如按钮,如果把暂停按钮也onExit了,那么就没办法重新开启游戏了。解决这个办法也很简单,那就是通过遍历子节点,一个一个地onExit暂停它们,同时排除掉不需要暂停的子节点。这样,主Layer虽然没有暂停,但是其所有的该暂停的子节点已经全部暂停了。

      见代码:

    auto vec = this->getChildren();
    for (auto &child : vec)
    {
        if (child->getTag() != PAUSE_MENU)
            child->onExit();
    }

      这样,基本就完成了暂停功能。但是还有两个非常重要的点,会对暂停产生致命影响,那就是:

      1.主Layer的事件监听还没有关闭,仍然在接收事件,如触摸;

      2.如果场景带有物理世界,那么物理世界还没有暂停,物理模拟还在继续。

      因此,还需要多调用两行代码才能完成真正的暂停:

    _eventDispatcher->pauseEventListenersForTarget(this);
    
    ((Scene*)this->getParent())->getPhysicsWorld()->setAutoStep(false);

      这样才算完成了一个完整的暂停效果。而且看上去效率挺快,实际操作上也没出现任何卡顿。最后就是重启游戏了,很简单,反过来调用onEnter即可:节点们,开工了!

  • 相关阅读:
    字典树(Trie)的学习笔记
    kmp学习笔记
    NOIP PJ游记
    Hash学习笔记
    神奇的差分法(内附树状数组的一点扩展)
    DLX算法一览
    A*与IDA*的奇妙之旅
    HDU_2553——n皇后问题,作弊
    HDU_2035——求A^B的最后三位数
    HDU_2034——集合A-B
  • 原文地址:https://www.cnblogs.com/demon90s/p/4495512.html
Copyright © 2020-2023  润新知