在 cocos2dx 中转换后场景冻结

Scene freezes after transitioning in cocos2dx

我从 GameLayerScene 转换到 HelloWorldScene 后,场景 (HelloWorldScene) 冻结并且按钮不可点击。使用replaceScene是不是错了?如何实现从主游戏到主菜单的 return 功能?我也使用 push 和 pop 但没有用。

GameLayerScene

Scene* GameLayer::createScene(int level)
{
    auto scene = Scene::create();
    auto layer = GameLayer::create(level);
    scene->addChild(layer);

    return scene;
}

GameLayer* GameLayer::create(int level)
{
    GameLayer *pRet = new GameLayer();
    pRet->init(level);
    pRet->autorelease();

    return pRet;
}

bool GameLayer::init(int level)
{
    if (!Layer::init())
        return false;

    auto touchListener = EventListenerTouchOneByOne::create();
    touchListener->setSwallowTouches(_swallowsTouches);
    touchListener->onTouchBegan = CC_CALLBACK_2(GameLayer::onTouchBegan, this);
    touchListener->onTouchMoved = CC_CALLBACK_2(GameLayer::onTouchMoved, this);
    touchListener->onTouchEnded = CC_CALLBACK_2(GameLayer::onTouchEnded, this);
    touchListener->onTouchCancelled = CC_CALLBACK_2(GameLayer::onTouchCancelled, this);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);

    _level = level; 

    //This will be shown when the pause is pressed.
    auto pauseLayer=LayerColor::create(Color4B::BLACK, WINSIZE.width, WINSIZE.height);
    auto pauseLabel=Label::createWithTTF("Paused", "fonts/Marker Felt.ttf", 24);
    pauseLabel->setPosition(WINSIZE.width / 2.0, (WINSIZE.height/ 2.0) + 100);
    pauseLayer->addChild(pauseLabel);
    // Add your required content to pauseLayer like pauseLabel
     auto resumeButton = cocos2d::ui::Button::create("resume.png");
     resumeButton->setPosition(Vec2(WINSIZE.width / 2.0, WINSIZE.height/ 2.0));
     resumeButton->addClickEventListener([pauseLayer](Ref*){
             //
             if(Director::getInstance()->isPaused()) {
                  Director::getInstance()->resume();
                  pauseLayer->setVisible(false);

              }
         });


         auto menuButton = cocos2d::ui::Button::create("menu.png");
              menuButton->setPosition(Vec2(WINSIZE.width / 2.0, (WINSIZE.height/ 2.0) - 100));
              menuButton->addClickEventListener([pauseLayer](Ref*){

                       Director::getInstance()->replaceScene(HelloWorldScene::createScene());
                       // Director::getInstance()->end();
                  });
    pauseLayer->addChild(resumeButton);
    pauseLayer->addChild(menuButton);
    pauseLayer->setVisible(false);
    pauseLayer->setOpacity(220);  // so that gameplay is slightly visible
    addChild(pauseLayer, ZOrder::Level);

AppDelegate

bool AppDelegate::applicationDidFinishLaunching()
{
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview)
    {
      glview = GLViewImpl::create("KaratePuzzle");
        director->setOpenGLView(glview);
    }

    director->setDisplayStats(false);
    director->setAnimationInterval(1.0 / 60);


    glview->setDesignResolutionSize(640, 1136, ResolutionPolicy::FIXED_WIDTH);

    auto scene = HelloWorldScene::createScene();
    director->runWithScene(scene);

    return true;
}

HelloWorldScene

Scene* HelloWorldScene::createScene()
{
    auto scene = Scene::create();
    auto layer = HelloWorldScene::create();
    scene->addChild(layer);
    return scene;
}

HelloWorldScene::HelloWorldScene()
{
}

HelloWorldScene::~HelloWorldScene()
{
}

bool HelloWorldScene::init()
{
    if (!Layer::init()) {
        return false;
    }
    CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("battle.mp3", true);

    auto director = Director::getInstance();
    auto winSize = director->getWinSize();

    auto background = Sprite::create("main_back.png");
    background->setPosition(Vec2(winSize.width / 2.0, winSize.height / 2.0));
    this->addChild(background);

    auto logo = Sprite::create("logo.png");
    logo->setPosition(Vec2(winSize.width / 2.0, winSize.height - 150));
    this->addChild(logo);

  auto menuButton = MenuItemImage::create("start.png","start.png","start.png",CC_CALLBACK_1(HelloWorldScene::ImageButton,this));
 // menuButton->setPosition(Vec2(winSize.width / 2.0, winSize.height /2.0));
    menuButton->setPosition(Vec2(winSize.width / 2.0, ((winSize.height /2.0) - 300)));
    menuButton->setScale(1.5f);
  auto blink = Sequence::create(FadeTo::create(0.5, 127),
                                    FadeTo::create(0.5, 255),
                                    NULL);
      menuButton->runAction(RepeatForever::create(blink));
      this->addChild(menuButton);

        auto moreButton = MenuItemImage::create("more.png","more.png","more.png",[](Ref*sender){
        std::string url = "https://play.google.com/xxx";
        cocos2d::Application::getInstance()->openURL(url);
        });
       winSize.height /2.0));
          moreButton->setPosition(Vec2(winSize.width / 2.0, 90));

            this->addChild(moreButton);
  auto menu = Menu::create(menuButton,moreButton, NULL);
  menu->setPosition(Point(0,0));
  this->addChild(menu);

  return true;
}

//Click event for menuButton
void HelloWorldScene::ImageButton(cocos2d::Ref *pSender) {
// stop background music
CocosDenshion::SimpleAudioEngine::getInstance()->stopBackgroundMusic();

            this->getEventDispatcher()->removeAllEventListeners();

            auto delay = DelayTime::create(0.5);

            auto startGame = CallFunc::create([]{
                auto scene = GameLayer::createScene();
                auto transition = TransitionPageTurn::create(0.5, scene, true);
                Director::getInstance()->replaceScene(transition);
               // CocosDenshion::SimpleAudioEngine::getInstance()->stopBackgroundMusic();
            });
            this->runAction(Sequence::create(delay,startGame,
                                             NULL));
}

void HelloWorldScene::onEnterTransitionDidFinish()
{
    //CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic(AudioUtils::getFileName("title").c_str());
}

HelloWorldScene.h

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__


#include "cocos2d.h"

class HelloWorldScene :public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();

    HelloWorldScene();
    virtual ~HelloWorldScene();

    bool init() override;
    void onEnterTransitionDidFinish() override;
    CREATE_FUNC(HelloWorldScene);
    void ImageButton(Ref *pSender);

};

#endif // __HELLOWORLD_SCENE_H__

GameLayerScene.h

#include "cocos2d.h"
#include <random>
#include "BallSprite.h"
#include "Character.h"

class GameLayer : public cocos2d::Layer
{
protected:

    enum class Direction
    {
        x,
        y,
    };


    enum ZOrder
    {
        BgForCharacter = 0,
        BgForPuzzle,
        Enemy,
        EnemyHp,
        Char,
        CharHp,
        Ball,
        Level,
        Result,
    };

    std::default_random_engine _engine;
    std::discrete_distribution<int> _distForBall; 
    std::uniform_int_distribution<int> _distForMember; 
    BallSprite* _movingBall; 
    bool _movedBall;
    bool _touchable; 
    int _maxRemovedNo; 
    int _chainNumber; 
    std::vector<std::map<BallSprite::BallType, int>> _removeNumbers;

    Character* _enemyData; 
    cocos2d::Sprite* _enemy; 
    cocos2d::ProgressTimer* _hpBarForEnemy; 

    cocos2d::Vector<Character*> _memberDatum; 
    cocos2d::Vector<cocos2d::Sprite*> _members; 
    cocos2d::Vector<cocos2d::ProgressTimer*> _hpBarForMembers; 

    int _level;
    int _nextLevel; 

    void initBackground(); 
    void initBalls(); 
    BallSprite* newBalls(BallSprite::PositionIndex positionIndex, bool visible); 
    BallSprite* getTouchBall(cocos2d::Point touchPos, BallSprite::PositionIndex withoutPosIndex = BallSprite::PositionIndex()); 
    void movedBall(); 
    void checksLinedBalls();
    bool existsLinedBalls(); 
    cocos2d::Map<int, BallSprite*> getAllBalls(); 
    bool isSameBallType(BallSprite::PositionIndex current, Direction direction); 
    void initBallParams();
    void checkedBall(BallSprite::PositionIndex current, Direction direction); 
    void removeAndGenerateBalls(); 
    void generateBalls(int xLineNum, int fallCount); 
    void animationBalls(); 
    void initEnemy(); 
    void initMembers(); 
    void calculateDamage(int &chainNum, int &healing, int &damage, std::set<int> &attackers); 
    bool isAttacker(BallSprite::BallType type, Character::Element element); 
    void attackToEnemy(int damage, std::set<int> attackers); 
    void healMember(int healing); 
    void attackFromEnemy(); 
    void endAnimation(); 
    cocos2d::Spawn* vibratingAnimation(int afterHp); 

    void initLevelLayer(); 
    void removeLevelLayer(float dt); 
    void winAnimation(); 
    void loseAnimation(); 
    void nextScene(float dt);

public:
    GameLayer(); 
    virtual bool init(int level); 
    static GameLayer* create(int level); 
    static cocos2d::Scene* createScene(int level = 1); 


    virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* unused_event);
    virtual void onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* unused_event);
    virtual void onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* unused_event);
    virtual void onTouchCancelled(cocos2d::Touch* touch, cocos2d::Event* unused_event);
    void PauseButton(Ref *pSender);
};

#endif

我没有测试过你的代码,但这个语句似乎有问题:

auto menu = Menu::create(menuButton,moreButton, NULL);

它会给出运行时异常,因为已经添加了 menuButton 和 moreButton。无法再次添加。

之所以能够解决problem.The的问题,是因为场景还在暂停,没有恢复。

auto menuButton = cocos2d::ui::Button::create("menu.png");
          menuButton->setPosition(Vec2(WINSIZE.width / 2.0, (WINSIZE.height/ 2.0) - 100));
          menuButton->addClickEventListener([pauseLayer](Ref*){
                    if (Director::getInstance()->isPaused()) {
                     Director::getInstance()->resume();
                    }
                   Director::getInstance()->replaceScene(HelloWorldScene::createScene());
                   // Director::getInstance()->end();
              });