[因?yàn)槲也欢-什么是狀態(tài)機(jī)編程(設(shè)計(jì)模式)(3)

上一篇文章寫完之后,我一直在想做一個(gè)游戲示例,想將之前學(xué)到的狀態(tài)機(jī)模式運(yùn)用在其中。然而一直遇到各種奇怪的bug(之后寫出來),所以一直沒有完成這件事。而且加之自己又犯懶了,所以我決定做一件更簡(jiǎn)單的事,以更容易接近的目標(biāo)來引誘懶的不行的自己。


廢話說完,來說正經(jīng)事了。前幾天認(rèn)真看了一篇 博客-游戲狀態(tài)機(jī)(侵立刪),覺得挺不錯(cuò)的,建議盆友們認(rèn)真看一看。

實(shí)現(xiàn)一個(gè)UI切換示例

為比較心急的伙伴放一個(gè)示例的Github鏈接

讀完博客之后,之前計(jì)劃的示例貌似有了頭緒,(廢話型)總結(jié)出來,實(shí)現(xiàn)一個(gè)游戲狀態(tài)機(jī)結(jié)構(gòu)需要進(jìn)行如下幾步:

  1. 分析示例(需求),劃分狀態(tài)。
  2. 找出需求中的狀態(tài)事件
  3. 寫一個(gè)狀態(tài)轉(zhuǎn)換表,使得需求更加明確。
  4. 寫一個(gè)控制類,包含狀態(tài)轉(zhuǎn)換方法,作為所有狀態(tài)的根,所有的狀態(tài)在這個(gè)根之上切換。
  5. 寫一個(gè)狀態(tài)基類,然后派生出需要的狀態(tài)類。
  6. 在每個(gè)狀態(tài)類中,寫好需要的事件,以及事件發(fā)生的處理(就是進(jìn)行狀態(tài)轉(zhuǎn)換)。

分析需求,劃分狀態(tài)

我要做一個(gè)簡(jiǎn)單的UI切換示例,所以簡(jiǎn)述需求就是: 打開程序進(jìn)入主界面,主界面中點(diǎn)擊開始游戲,進(jìn)入游戲界面,游戲界面中點(diǎn)擊結(jié)束游戲,進(jìn)入結(jié)算界面,結(jié)算界面可以點(diǎn)擊回到主界面,進(jìn)入主界面,也可以點(diǎn)擊重新開始游戲,再次進(jìn)入游戲界面。

找出狀態(tài)和事件

從需求描述來看,狀態(tài)有三個(gè):

  1. 主界面
  2. 游戲界面
  3. 結(jié)算界面

事件有四個(gè):

  1. 主界面->點(diǎn)擊開始游戲按鈕
  2. 游戲界面->點(diǎn)擊游戲結(jié)束按鈕
  3. 結(jié)算界面->點(diǎn)擊回到主頁按鈕
  4. 結(jié)算界面->點(diǎn)擊重新游戲按鈕

狀態(tài)轉(zhuǎn)換表

然后(裝模作樣的)畫了一個(gè)狀態(tài)轉(zhuǎn)換表:

狀態(tài) 事件 下一狀態(tài)
主界面 點(diǎn)擊開始游戲 游戲界面
游戲界面 點(diǎn)擊游戲結(jié)束 結(jié)算界面
結(jié)算界面 點(diǎn)擊回到主界面 主界面
點(diǎn)擊重新游戲 游戲界面

寫一個(gè)控制類

之前一篇文章中有提到過的,在Cocos2d-x游戲開發(fā)中,剛好使用Scene來作為控制器,由Scene來控制各層的出現(xiàn)和消失。

這里貼出Scene的源碼(完整的源文件,包括了后續(xù)步驟才會(huì)出現(xiàn)的狀態(tài)基類,以及派生的狀態(tài)類):
QFLGameTwoScene.hpp

//
//  QFLGameTwoScene.hpp
//  QFLTest
//
//  Created by QuFangliu on 16/10/8.
//
//

#ifndef QFLGameTwoScene_hpp
#define QFLGameTwoScene_hpp

#include <stdio.h>
#include "cocos2d.h"
#include "QFLGameTwoStateBase.hpp"

class QFLGameTwoScene : public cocos2d::Scene   
{
CC_CONSTRUCTOR_ACCESS:
    QFLGameTwoScene();
    virtual ~QFLGameTwoScene();
    virtual bool init();
    CREATE_FUNC(QFLGameTwoScene);
    
public:
    void addUI();               //添加UI,黑色背景
    void initGame();            //初始化游戲,進(jìn)入一個(gè)初始狀態(tài)
    void addEventListener();    //添加事件監(jiān)聽,需要切換狀態(tài)時(shí)通過發(fā)送自定義事件來實(shí)現(xiàn)
    
    //切換狀態(tài)的函數(shù)
    void ChangeState(GameTwoState* pState);
    
private:
    GameTwoState* m_pCurrentState;  //當(dāng)前狀態(tài)
};

#endif /* QFLGameTwoScene_hpp */

QFLGameTwoScene.cpp

//
//  QFLGameTwoScene.cpp
//  QFLTest
//
//  Created by QuFangliu on 16/10/8.
//
//

#include "QFLGameTwoScene.hpp"

#include "QFLTools/QFLHelper.hpp"

//基類
#include "QFLGameTwoStateBase.hpp"

//狀態(tài)類
#include "QFLGameTwoMainLayer.hpp"
#include "QFLGameTwoGameLayer.hpp"
#include "QFLGameTwoResultLayer.hpp"

USING_NS_CC;

QFLGameTwoScene::QFLGameTwoScene()
{
    
}

QFLGameTwoScene::~QFLGameTwoScene()
{
    
}
bool QFLGameTwoScene::init()
{
    if (!Scene::init()) {
        return false;
    }
    else {
        this->addUI();
        this->addEventListener();
        this->initGame();
        return true;
    }
}

void QFLGameTwoScene::addUI()
{
    //黑色背景
    auto pLayer = QFL_HELPER->getColorfulLayer();
    QFL_HELPER->addNoTouchListener(pLayer);
    this->addChild(pLayer);
}

void QFLGameTwoScene::initGame()
{
    //進(jìn)入一個(gè)初始狀態(tài)
    log("游戲開始");
    m_pCurrentState = QFLGameTwoMainLayer::create();
    m_pCurrentState->Enter(this);
}

void QFLGameTwoScene::addEventListener()
{
    Director::getInstance()->getEventDispatcher()->addCustomEventListener(GameTwoEvent::Main_Start, [=](EventCustom* pEvent){
        log("[Event]->Main_Start");
        this->ChangeState(QFLGameTwoGameLayer::create());
    });
    Director::getInstance()->getEventDispatcher()->addCustomEventListener(GameTwoEvent::Game_Over, [=](EventCustom* pEvent){
        log("[Event]->Game_Over");
        this->ChangeState(QFLGameTwoResultLayer::create());
    });
    Director::getInstance()->getEventDispatcher()->addCustomEventListener(GameTwoEvent::Result_Home, [=](EventCustom* pEvent){
        log("[Event]->Result_Home");
        this->ChangeState(QFLGameTwoMainLayer::create());
    });
    Director::getInstance()->getEventDispatcher()->addCustomEventListener(GameTwoEvent::Result_Replay, [=](EventCustom* pEvent){
        log("[Event]->Result_Replay");
        this->ChangeState(QFLGameTwoGameLayer::create());
    });
}

void QFLGameTwoScene::ChangeState(GameTwoState *pState)
{
    //舊狀態(tài)退出
    m_pCurrentState->Exit(this);
    
    //保存新狀態(tài)
    m_pCurrentState = pState;
    
    //新狀態(tài)進(jìn)入
    m_pCurrentState->Enter(this);
}

QFLTools/QFLHelper.hpp 這個(gè)文件是作為一個(gè)工具類存在的,本示例所有源碼在我的Github

上面可以看到,Scene中主要包含了:

  1. void ChangeState(GameTwoState* pState);用于狀態(tài)切換
  2. GameTwoState* m_pCurrentState;用于記錄當(dāng)前狀態(tài)
  3. void addEventListener();用于監(jiān)聽切換狀態(tài)事件
  4. void initGame();用于進(jìn)入初始狀態(tài)

包含了以上內(nèi)容,本示例中的這個(gè)Scene就能起到控制器的作用了。

寫一個(gè)狀態(tài)基類

狀態(tài)基類是很有必要的,為了達(dá)到各個(gè)同級(jí)狀態(tài)都能通過同一個(gè)控制器來進(jìn)行狀態(tài)轉(zhuǎn)換的目標(biāo),各個(gè)狀態(tài)類進(jìn)行切換時(shí)必須有一套統(tǒng)一的流程。
這里貼出本示例中狀態(tài)基類的源碼:
QFLGameTwoStateBase.hpp

//
//  QFLGameTwoStateBase.hpp
//  QFLTest
//
//  Created by QuFangliu on 16/10/8.
//
//

#ifndef QFLGameTwoStateBase_hpp
#define QFLGameTwoStateBase_hpp

#include <stdio.h>
#include "cocos2d.h"

//State的基類
class GameTwoState
{
public:
    virtual ~GameTwoState() {}
    virtual void Enter(cocos2d::Scene* pLayer) = 0;
    virtual void Execute() = 0;
    virtual void Exit(cocos2d::Scene* pLayer) = 0;
};

#define SC(__type__) static const __type__
//游戲中的事件(通過事件來進(jìn)行狀態(tài)切換)
namespace GameTwoEvent {
    SC(std::string) Main_Start      = "Event_Main_Start";   //[Main]開始游戲的事件
    SC(std::string) Game_Over       = "Event_Game_Over";    //[Game]結(jié)束游戲的事件
    SC(std::string) Result_Home     = "Event_Result_Home";  //[Result]結(jié)算界面回主頁
    SC(std::string) Result_Replay   = "Event_Result_Replay";//[Result]結(jié)算界面重新開始
}

#endif /* QFLGameTwoStateBase_hpp */

這個(gè)源文件中包含了:

  1. class GameTwoState 狀態(tài)基類
  2. virtual void Enter(cocos2d::Scene* pLayer) = 0;狀態(tài)進(jìn)入的處理
  3. virtual void Execute() = 0;本狀態(tài)執(zhí)行的方法
  4. virtual void Exit(cocos2d::Scene* pLayer) = 0;狀態(tài)退出的處理
  5. namespace GameTwoEvent包含狀態(tài)轉(zhuǎn)換事件的namespace

所有的派生狀態(tài)類都會(huì)include這個(gè)文件,實(shí)現(xiàn)虛基類GameTwoState中的方法,所以所有的狀態(tài)類都有統(tǒng)一的切換流程:

  1. last_state->exit
  2. current_state->enter
  3. current_state->execute

而且在完成某個(gè)事件,需要進(jìn)行狀態(tài)轉(zhuǎn)換時(shí),可以通過發(fā)送自定義事件來完成消息的傳遞,自定義事件名放在這里也是為了方便起見。

每個(gè)狀態(tài)類中寫好需要的事件及處理

這里直接貼出幾個(gè)State的源碼了,其中包含注釋,廢話就不重復(fù)再寫了:

MainState源碼

QFLGameTwoMainLayer.hpp

//
//  QFLGameTwoMainLayer.hpp
//  QFLTest
//
//  Created by QuFangliu on 16/10/8.
//
//

#ifndef QFLGameTwoMainLayer_hpp
#define QFLGameTwoMainLayer_hpp

#include <stdio.h>
#include "cocos2d.h"
#include "QFLGameTwoStateBase.hpp"

class QFLGameTwoMainLayer : public cocos2d::Layer, public GameTwoState
{
public:
    QFLGameTwoMainLayer();
    virtual ~QFLGameTwoMainLayer();
    virtual bool init() override;
    CREATE_FUNC(QFLGameTwoMainLayer);
    
    //實(shí)現(xiàn)StateBase的狀態(tài)切換所需方法
    void Enter(cocos2d::Scene* pLayer) override;
    void Execute() override;
    void Exit(cocos2d::Scene* pLayer) override;
    
private:
    void addUI();   //添加背景UI,添加按鈕等
};

#endif /* QFLGameTwoMainLayer_hpp */

QFLGameTwoMainLayer.cpp

//
//  QFLGameTwoMainLayer.cpp
//  QFLTest
//
//  Created by QuFangliu on 16/10/8.
//
//

#include "QFLGameTwoMainLayer.hpp"

#include "QFLTools/QFLHelper.hpp"

USING_NS_CC;

QFLGameTwoMainLayer::QFLGameTwoMainLayer()
{
    
}

QFLGameTwoMainLayer::~QFLGameTwoMainLayer()
{
    
}

bool QFLGameTwoMainLayer::init()
{
    if (!Layer::init()) {
        return false;
    }
    else {
        this->addUI();
        return true;
    }
}

void QFLGameTwoMainLayer::Enter(cocos2d::Scene* pLayer)
{
    log("<Enter>\t\t->MainLayer");
    
    //添加到Scene中
    pLayer->addChild(this);
    
    //執(zhí)行各種事件
    this->Execute();
}

void QFLGameTwoMainLayer::Execute()
{
    log("<Execute>\t->MainLayer");  //執(zhí)行內(nèi)容只是打印一個(gè)Log
}

void QFLGameTwoMainLayer::Exit(cocos2d::Scene* pLayer)
{
    log("<Exit>\t\t->MainLayer\n");
    
    //移除
    this->removeFromParentAndCleanup(true);
}

void QFLGameTwoMainLayer::addUI()
{
    //黑色背景
    auto pLayer = QFL_HELPER->getColorfulLayer();
    QFL_HELPER->addNoTouchListener(pLayer);
    this->addChild(pLayer);
    
    //MainLogo
    auto pLogo = Label::createWithSystemFont("MainLayer", "", 50);
    pLogo->setPosition(Vec2(SCREEN_CENTER.x, SCREEN_CENTER.y + 60));
    this->addChild(pLogo);
    
    //菜單
    auto pMenu = Menu::create();
    pMenu->setPosition(Vec2::ZERO);
    this->addChild(pMenu);
    
    //按鈕,點(diǎn)擊發(fā)送游戲開始事件
    auto pStart = MenuItemFont::create("Start", [=](cocos2d::Ref* pRef){
        Director::getInstance()->getEventDispatcher()->dispatchCustomEvent(GameTwoEvent::Main_Start);
    });
    pStart->setPosition(Vec2(SCREEN_CENTER.x, SCREEN_CENTER.y - 100));
    pMenu->addChild(pStart);
}

GameState源碼

QFLGameTwoGameLayer.hpp

//
//  QFLGameTwoGameLayer.hpp
//  QFLTest
//
//  Created by QuFangliu on 16/10/8.
//
//

#ifndef QFLGameTwoGameLayer_hpp
#define QFLGameTwoGameLayer_hpp

#include <stdio.h>
#include "cocos2d.h"
#include "QFLGameTwoStateBase.hpp"

class QFLGameTwoGameLayer : public cocos2d::Layer, public GameTwoState
{
public:
    QFLGameTwoGameLayer();
    virtual ~QFLGameTwoGameLayer();
    virtual bool init() override;
    CREATE_FUNC(QFLGameTwoGameLayer);
    
    //實(shí)現(xiàn)StateBase的狀態(tài)切換所需方法
    void Enter(cocos2d::Scene* pLayer) override;
    void Execute() override;
    void Exit(cocos2d::Scene* pLayer) override;
    
private:
    void addUI();
};

#endif /* QFLGameTwoGameLayer_hpp */

QFLGameTwoGameLayer.cpp

//
//  QFLGameTwoGameLayer.cpp
//  QFLTest
//
//  Created by QuFangliu on 16/10/8.
//
//

#include "QFLGameTwoGameLayer.hpp"

#include "QFLTools/QFLHelper.hpp"

USING_NS_CC;

QFLGameTwoGameLayer::QFLGameTwoGameLayer()
{
    
}

QFLGameTwoGameLayer::~QFLGameTwoGameLayer()
{
    
}

bool QFLGameTwoGameLayer::init()
{
    if (!Layer::init()) {
        return false;
    }
    else {
        this->addUI();
        return true;
    }
}

void QFLGameTwoGameLayer::addUI()
{
    //黑色背景
    auto pLayer = QFL_HELPER->getColorfulLayer();
    QFL_HELPER->addNoTouchListener(pLayer);
    this->addChild(pLayer);
    
    //GameLogo
    auto pLogo = Label::createWithSystemFont("GameLayer", "", 50);
    pLogo->setPosition(Vec2(SCREEN_CENTER.x, SCREEN_CENTER.y + 60));
    this->addChild(pLogo);
    
    //菜單
    auto pMenu = Menu::create();
    pMenu->setPosition(Vec2::ZERO);
    this->addChild(pMenu);
    
    //按鈕,點(diǎn)擊發(fā)送游戲結(jié)束事件
    auto pOver = MenuItemFont::create("GameOver", [=](cocos2d::Ref* pRef){
        Director::getInstance()->getEventDispatcher()->dispatchCustomEvent(GameTwoEvent::Game_Over);
    });
    pOver->setPosition(Vec2(SCREEN_CENTER.x, SCREEN_CENTER.y - 100));
    pMenu->addChild(pOver);
}

void QFLGameTwoGameLayer::Enter(cocos2d::Scene* pLayer)
{
    log("<Enter>\t\t->GameLayer");
    
    //添加到Scene中
    pLayer->addChild(this);
    
    //執(zhí)行游戲
    this->Execute();
}

void QFLGameTwoGameLayer::Execute()
{
    log("<Execute>\t->GameLayer");
}

void QFLGameTwoGameLayer::Exit(cocos2d::Scene* pLayer)
{
    log("<Exit>\t\t->GameLayer\n");
    
    //移除游戲
    this->removeFromParentAndCleanup(true);
}

ResultState源碼

QFLGameTwoResultLayer.hpp

//
//  QFLGameTwoResultLayer.hpp
//  QFLTest
//
//  Created by QuFangliu on 16/10/8.
//
//

#ifndef QFLGameTwoResultLayer_hpp
#define QFLGameTwoResultLayer_hpp

#include <stdio.h>
#include "cocos2d.h"
#include "QFLGameTwoStateBase.hpp"

class QFLGameTwoResultLayer : public cocos2d::Layer, public GameTwoState
{
public:
    QFLGameTwoResultLayer();
    virtual ~QFLGameTwoResultLayer();
    virtual bool init() override;
    CREATE_FUNC(QFLGameTwoResultLayer);
    
    //實(shí)現(xiàn)StateBase的狀態(tài)切換所需方法
    void Enter(cocos2d::Scene* pLayer) override;
    void Execute() override;
    void Exit(cocos2d::Scene* pLayer) override;
    
private:
    void addUI();
};
#endif /* QFLGameTwoResultLayer_hpp */

QFLGameTwoResultLayer.cpp

//
//  QFLGameTwoResultLayer.cpp
//  QFLTest
//
//  Created by QuFangliu on 16/10/8.
//
//

#include "QFLGameTwoResultLayer.hpp"
#include "QFLTools/QFLHelper.hpp"

USING_NS_CC;

QFLGameTwoResultLayer::QFLGameTwoResultLayer()
{
    
}

QFLGameTwoResultLayer::~QFLGameTwoResultLayer()
{
    
}

bool QFLGameTwoResultLayer::init()
{
    if (!Layer::init()) {
        return false;
    }
    else {
        this->addUI();
        return true;
    }
}

void QFLGameTwoResultLayer::addUI()
{
    //黑色背景
    auto pLayer = QFL_HELPER->getColorfulLayer();
    QFL_HELPER->addNoTouchListener(pLayer);
    this->addChild(pLayer);
    
    //GameLogo
    auto pLogo = Label::createWithSystemFont("ResultLayer", "", 50);
    pLogo->setPosition(Vec2(SCREEN_CENTER.x, SCREEN_CENTER.y + 60));
    this->addChild(pLogo);
    
    //菜單
    auto pMenu = Menu::create();
    pMenu->setPosition(Vec2::ZERO);
    this->addChild(pMenu);
    
    //按鈕,點(diǎn)擊發(fā)送會(huì)到主界面事件
    auto pHome = MenuItemFont::create("Home", [=](cocos2d::Ref* pRef){
        Director::getInstance()->getEventDispatcher()->dispatchCustomEvent(GameTwoEvent::Result_Home);
    });
    pHome->setPosition(Vec2(SCREEN_CENTER.x, SCREEN_CENTER.y - 100));
    pMenu->addChild(pHome);
    
    //按鈕,點(diǎn)擊發(fā)送重新開始游戲事件
    auto pReplay = MenuItemFont::create("Replay", [=](cocos2d::Ref* pRef){
        Director::getInstance()->getEventDispatcher()->dispatchCustomEvent(GameTwoEvent::Result_Replay);
    });
    pReplay->setPosition(Vec2(SCREEN_CENTER.x, SCREEN_CENTER.y - 150));
    pMenu->addChild(pReplay);
}

void QFLGameTwoResultLayer::Enter(cocos2d::Scene* pLayer)
{
    log("<Enter>\t\t->ResultLayer");
    
    //添加到Scene中
    pLayer->addChild(this);
    
    //執(zhí)行游戲
    this->Execute();
}

void QFLGameTwoResultLayer::Execute()
{
    log("<Execute>\t->ResultLayer");
}

void QFLGameTwoResultLayer::Exit(cocos2d::Scene* pLayer)
{
    log("<Exit>\t\t->ResultLayer\n");
    
    //移除游戲
    this->removeFromParentAndCleanup(true);
}

到這里,上面所提到的步驟全部進(jìn)行完了。這個(gè)UI切換的狀態(tài)機(jī)示例也就完成了。


運(yùn)行效果

在AppDelegate.cpp中,直接進(jìn)入Scene中:

auto pScene = QFLGameTwoScene::create();
director->runWithScene(pScene);

進(jìn)入主界面:

MainState.jpeg

此時(shí)的Log:

游戲開始
<Enter> ->MainLayer
<Execute> ->MainLayer

點(diǎn)擊Start,進(jìn)入游戲界面:

GameState.jpeg

此時(shí)的Log:

游戲開始
<Enter> ->MainLayer
<Execute> ->MainLayer
[Event]->Main_Start

<Exit> ->MainLayer
<Enter> ->GameLayer
<Execute> ->GameLayer

點(diǎn)擊Over,進(jìn)入結(jié)算界面:

ResultState.jpeg

此時(shí)的Log:

游戲開始
<Enter> ->MainLayer
<Execute> ->MainLayer
[Event]->Main_Start
<Exit> ->MainLayer

<Enter> ->GameLayer
<Execute> ->GameLayer
[Event]->Game_Over
<Exit> ->GameLayer

<Enter> ->ResultLayer
<Execute> ->ResultLayer

點(diǎn)擊Replay,重新進(jìn)入游戲界面:
此時(shí)的Log:

游戲開始
<Enter> ->MainLayer
<Execute> ->MainLayer
[Event]->Main_Start
<Exit> ->MainLayer

<Enter> ->GameLayer
<Execute> ->GameLayer
[Event]->Game_Over
<Exit> ->GameLayer

<Enter> ->ResultLayer
<Execute> ->ResultLayer
[Event]->Result_Replay
<Exit> ->ResultLayer

<Enter> ->GameLayer
<Execute> ->GameLayer

點(diǎn)擊Over,再次進(jìn)入結(jié)算界面,然后在結(jié)算界面點(diǎn)擊Home,回到主界面
上面的兩次操作完成后,Log如下:

游戲開始
<Enter> ->MainLayer
<Execute> ->MainLayer
[Event]->Main_Start
<Exit> ->MainLayer

<Enter> ->GameLayer
<Execute> ->GameLayer
[Event]->Game_Over
<Exit> ->GameLayer

<Enter> ->ResultLayer
<Execute> ->ResultLayer
[Event]->Result_Replay
<Exit> ->ResultLayer

<Enter> ->GameLayer
<Execute> ->GameLayer
[Event]->Game_Over
<Exit> ->GameLayer

<Enter> ->ResultLayer
<Execute> ->ResultLayer
[Event]->Result_Home
<Exit> ->ResultLayer

<Enter> ->MainLayer
<Execute> ->MainLayer


總結(jié)

這里用FSM實(shí)現(xiàn)UI切換示例只是眾多方法中的一種,暫時(shí)還沒有去比較它們的優(yōu)劣。(使用markdown編輯器的經(jīng)驗(yàn)值+1)

例如:在狀態(tài)基類文件中,添加一個(gè)狀態(tài)枚舉類型enum StateTypevoid ChangeState轉(zhuǎn)換狀態(tài)時(shí)不再傳遞一個(gè)GameTwoState *pState指針,而是傳遞一個(gè)狀態(tài)枚舉值StateType,這種方法在某些情況下很有效。

例如:不用在void Enter中傳入一個(gè)cocos2d::Scene* pLayer指針,而是在void ChangeState中生成新的狀態(tài)類,并addChild到Scene中。不用在void Exit中傳入一個(gè)cocos2d::Scene* pLayer指針,直接使用removeFromParentAndClean方法就能從Scene中刪除。

可能性多種多樣,如果有小伙伴比較過這些方法。求留言告知,求分享經(jīng)驗(yàn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容