探秘Unity游戲開(kāi)發(fā)中的狀態(tài)設(shè)計(jì)模式
一、狀態(tài)模式定義
狀態(tài)模式(state)在GoF中的解釋?zhuān)?/p>
讓一個(gè)對(duì)象的行為隨著內(nèi)部狀態(tài)的改變而改變,而該對(duì)象也想換了類(lèi)一樣。
二、實(shí)現(xiàn)范例
結(jié)構(gòu)圖:
Context(狀態(tài)擁有者)
/// <summary> /// Describe:狀態(tài)擁有者 /// Note:是一個(gè)具有“狀態(tài)”屬性的類(lèi),可以制定相關(guān)的接口,讓外界能夠得知狀態(tài)的改變或通過(guò)操作讓狀態(tài)改變。 /// 比如:游戲角色有潛行,攻擊、施法等狀態(tài);好友上線,脫機(jī)、忙碌等狀態(tài); /// GoF使用TCP聯(lián)網(wǎng)為例,有已連接、等待連接、短線等狀態(tài); /// </summary> public class Context { State state = null; public void Request(int Value) { state.Handle(Value); } public void SetState(State state) { this.state = state; } }
State(狀態(tài)接口類(lèi))
/// <summary> /// Describe:狀態(tài)接口類(lèi) /// Note:指定狀態(tài)的接口,負(fù)責(zé)規(guī)范Context(狀態(tài)擁有者)在特定狀態(tài)下要表現(xiàn)的行為。 /// </summary> public abstract class State { protected Context m_Context = null; public State(Context context) { m_Context = context; } public abstract void Handle(int Value); }
ConcreteState(具體狀態(tài)類(lèi))
/* Describe:具體狀態(tài)類(lèi) Note: 1、繼承自State(狀態(tài)接口類(lèi)) 2、實(shí)現(xiàn)Context(狀態(tài)擁有者)在特定狀態(tài)下該有的行為。 */ //狀態(tài)A public class ConcreteStateA : State { public ConcreteStateA(Context context) : base(context) { } public override void Handle(int Value) { if (Value>10) { m_Context.SetState(new ConcreteStateB(m_Context)); } } } //狀態(tài)A public class ConcreteStateB : State { public ConcreteStateB(Context context) : base(context) { } public override void Handle(int Value) { if (Value > 10) { m_Context.SetState(new ConcreteStateC(m_Context)); } } } //狀態(tài)A public class ConcreteStateC : State { public ConcreteStateC(Context context) : base(context) { } public override void Handle(int Value) { if (Value > 10) { m_Context.SetState(new ConcreteStateA(m_Context)); } } }
三、使用狀態(tài)模式(state)實(shí)現(xiàn)游戲場(chǎng)景的轉(zhuǎn)換
場(chǎng)景結(jié)構(gòu)示意圖:
ISceneState 場(chǎng)景類(lèi)接口
/// <summary> /// Describe:場(chǎng)景類(lèi)接口 /// Note:定義場(chǎng)景轉(zhuǎn)換和執(zhí)行時(shí)需要調(diào)用的方法。 /// </summary> public class ISceneState { //狀態(tài)名稱(chēng) private string m_StateName = "ISceneState"; public string StateName { get => m_StateName; set => m_StateName = value; } //控制者 protected SceneStateController m_Controller = null; //建造者 public ISceneState(SceneStateController controller) { m_Controller = controller; } //開(kāi)始 public virtual void StateBegin() { } //結(jié)束 public virtual void StateEnd() { } //更新 public virtual void StateUpdate() { } //結(jié)束 public override string ToString() { return $"[I_SceneState: StateName={StateName}]"; } }
三個(gè)可切換場(chǎng)景(主畫(huà)面場(chǎng)景,主畫(huà)面場(chǎng)景,戰(zhàn)斗場(chǎng)景)
主畫(huà)面場(chǎng)景
/// <summary> /// Describe:開(kāi)始場(chǎng)景 /// </summary> public class StartState : ISceneState { public StartState(SceneStateController controller) : base(controller) { this.StateName="StartState"; } //開(kāi)始 public override void StateBegin() { //可在此進(jìn)行游戲數(shù)據(jù)加載和初始化 } //更新 public override void StateUpdate() { //更換為 m_Controller.SetState(new MainMenuState(m_Controller), "MainMenuScene"); } }
主畫(huà)面場(chǎng)景
/// <summary> /// Author:maki /// Time:2021-12-2 /// Describe:主畫(huà)面場(chǎng)景 /// </summary> public class MainMenuState:ISceneState { private Button tmpBtn; public MainMenuState(SceneStateController controller) : base(controller) { this.StateName = "MainMenuState"; } //開(kāi)始 public override void StateBegin() { //獲取開(kāi)始按鈕 // tmpBtn=UITool.GetUIComponent<Button>("StartGameBtn"); tmpBtn?.onClick.AddListener(()=>OnStartGameBtnClick(tmpBtn)); } //開(kāi)始游戲 private void OnStartGameBtnClick(Button tmpBtn) { m_Controller.SetState(new BattleState(m_Controller), "BattleScene"); } }
戰(zhàn)斗場(chǎng)景
/// <summary> /// Author:maki /// Time:2021-12-2 /// Describe:戰(zhàn)斗場(chǎng)景 /// </summary> public class BattleState:ISceneState { public BattleState(SceneStateController controller) : base(controller) { this.StateName = "BattleState"; } //開(kāi)始 public override void StateBegin() { } //結(jié)束 public override void StateEnd() { } //更新 public override void StateUpdate() { //輸入 InputProcess(); //游戲邏輯 //游戲是否結(jié)束 m_Controller.SetState(new MainMenuState(m_Controller), "MainMenuState"); } //輸入 private void InputProcess() { //玩家輸入判斷程序代碼。。。 } }
SceneStateController-場(chǎng)景狀態(tài)控制者
/// <summary> /// Author:maki /// Time:2021-12-2 /// Describe:場(chǎng)景狀態(tài)的擁有者(Context),保持當(dāng)前游戲場(chǎng)景狀態(tài),并作為與GameLoop類(lèi)互動(dòng)的接口, /// 除此以外,也是U3D場(chǎng)景轉(zhuǎn)換的地方。 /// </summary> public class SceneStateController { private ISceneState m_State; private bool m_bRunBegin = false; public SceneStateController() { } //設(shè)置狀態(tài) public void SetState(ISceneState state, string loadSceneName) { m_bRunBegin = false; //載入場(chǎng)景 LoadScene(loadSceneName); //通知前一個(gè)State結(jié)束 if (m_State != null) m_State.StateEnd(); //設(shè)置 m_State = state; } //載入場(chǎng)景 private void LoadScene(string loadSceneName) { if (string.IsNullOrEmpty(loadSceneName)) { return; } SceneManager.LoadScene(loadSceneName); // Application.LoadLevel(loadSceneName); 過(guò)時(shí) } //更新 public void StateUpdate() { //通知新的State開(kāi)始 if (m_State != null && m_bRunBegin == false) { m_State.StateBegin(); m_bRunBegin = true; } if (m_State != null) { m_State.StateUpdate(); } } }
GameLoop-游戲主循環(huán)類(lèi)
/// <summary> /// Author:maki /// Time:2021-12-2 /// Describe:游戲主循環(huán)類(lèi) /// Note:包含初始化游戲和定期調(diào)用更新操作 /// </summary> public class GameLoop:MonoBehaviour { //場(chǎng)景狀態(tài) SceneStateController sceneStateController = new SceneStateController(); void Awake() { // 轉(zhuǎn)換場(chǎng)景不會(huì)被刪除 GameObject.DontDestroyOnLoad(gameObject); //隨機(jī)數(shù)種子 Random.seed = (int)System.DateTime.Now.Ticks; } private void Start() { //設(shè)置起始場(chǎng)景 sceneStateController.SetState(new StartState(sceneStateController), ""); } private void Update() { sceneStateController.StateUpdate(); } }
四、使用狀態(tài)模式的優(yōu)點(diǎn)
優(yōu)點(diǎn)
- 減少錯(cuò)誤的發(fā)生并降低維護(hù)難度;
- 狀態(tài)執(zhí)行環(huán)境單一化;
- 項(xiàng)目之間可以共享場(chǎng)景;
具體來(lái)說(shuō),使用狀態(tài)模式可以清楚地了解某個(gè)場(chǎng)景狀態(tài)執(zhí)行時(shí)所需要配合使用的類(lèi)對(duì)象,并且減少因新增狀態(tài)而需要大量修改現(xiàn)有程序代碼的維護(hù)成本。
缺點(diǎn)
在應(yīng)用有大量狀態(tài)的系統(tǒng)時(shí),會(huì)遇到“產(chǎn)生過(guò)多狀態(tài)類(lèi)”的情況,此時(shí)會(huì)伴隨著類(lèi)爆炸的問(wèn)題。
到此這篇關(guān)于探秘Unity游戲開(kāi)發(fā)中的狀態(tài)設(shè)計(jì)模式的文章就介紹到這了,更多相關(guān)Unity狀態(tài)模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#?將數(shù)據(jù)庫(kù)SqlServer數(shù)據(jù)綁定到類(lèi)中的過(guò)程詳解
本文講述的是讀取數(shù)據(jù)庫(kù)中數(shù)據(jù)的常用做法,即將數(shù)據(jù)庫(kù)中的數(shù)據(jù)綁定到創(chuàng)建的類(lèi)中,再將類(lèi)綁定到DataGridView的數(shù)據(jù)源中的做法,對(duì)C#將SqlServer數(shù)據(jù)綁定到類(lèi)中感興趣的朋友一起看看吧2022-06-06c# 9.0新特性nint和Pattern matching的使用方法
這篇文章主要介紹了c# 9.0新特性nint和Pattern matching的使用方法,文中講解非常細(xì)致,幫助你更好的學(xué)習(xí)c# 9.0,有需求的朋友可以參考下2020-06-06Unity Shader實(shí)現(xiàn)徑向模糊效果
這篇文章主要為大家詳細(xì)介紹了Unity Shader實(shí)現(xiàn)徑向模糊效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08C#使用ThreadPriority設(shè)置線程優(yōu)先級(jí)
這篇文章介紹了C#使用ThreadPriority設(shè)置線程優(yōu)先級(jí)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04C# WinForm自動(dòng)更新程序之文件上傳操作詳解
這篇文章主要為大家詳細(xì)介紹了C# WinForm自動(dòng)更新程序中文件上傳操作,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以了解一下2022-10-10C#很簡(jiǎn)單而又很經(jīng)典的一句代碼實(shí)例
這篇文章主要給大家分享介紹了關(guān)于C#很簡(jiǎn)單而又很經(jīng)典的一句代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07C#中使用Lambda表達(dá)式自定義比較器實(shí)現(xiàn)兩個(gè)列表合并實(shí)例
這篇文章主要介紹了C#中使用Lambda表達(dá)式自定義比較器實(shí)現(xiàn)兩個(gè)列表的合并實(shí)例,本文給出示例代碼和運(yùn)行效果,需要的朋友可以參考下2014-10-10