状态模式
- 角色状态
- AI状态
- 账号登陆状态
- 场景状态
- 动画机状态
1.简单的状态控制
https://www.youtube.com/watch?v=r-RCfmQqLA0
(作者本意为避免if嵌套,避免定义过多变量进行开关控制)
有人指出这不是一个好办法,因为在添加状态时要不断为新状态创建新的类,一个方法占据一个单独的类,过多的类反而使管理和可读性变差。
状态管理利用字典返回一个状态标志。
class Character:MonoBenaviour{characterState state;void Update(){state = state.handleInput();}}
class characterState{virtual public characterState handleInput(){return this;}}class JumpingState:characterState{override public characterState handleInput(){return this;}}class IdleState:characterState{override public characterState handleInput(){if(按下跳跃键)return new JumpingState();return this;}}
2.场景执行用状态管理
https://zhuanlan.zhihu.com/p/85095810
和上个部分类似,说明更详细一些
以场景的转换作为示例展示状态模式
- GameLoop:游戏的主循环,继承自MonoBehavior,包含了游戏的初始化和循环更新操作,同时也是设置起始场景的地方。
- SceneStateController:场景状态的拥有者,对应上面说的Context(状态拥有者),执行场景转换的地方,在GameLoop中完成创建。
- SceneState:场景的抽象类,定义了场景转换和执行时所需的方法。
StartState、MainMenuState、BattleState:分别对应了开始场景、主界面场景、战斗场景的具体实现类。
public class GameLoop : MonoBehaviour{// 场景状态持有者SceneStateController m_SceneStateController = new SceneStateController();//void Awake(){// 保证场景切换时不会被删除GameObject.DontDestroyOnLoad( this.gameObject );}// Use this for initializationvoid Start (){// 设定起始场景m_SceneStateController.SetState(new StartState(m_SceneStateController), "");}// Update is called once per framevoid Update (){m_SceneStateController.StateUpdate();}}
public class SceneStateController{private SceneState m_State;private bool m_bRunBegin = false;public SceneStateController(){}// 设定状态public void SetState(SceneState State, string LoadSceneName){//Debug.Log ("SetState:"+State.ToString());m_bRunBegin = false;// 载入场景LoadScene(LoadSceneName);// 通知前一个State結束if( m_State != null )m_State.StateEnd();// 设定m_State=State;}// 载入private void LoadScene(string LoadSceneName){if( LoadSceneName==null || LoadSceneName.Length == 0 )return ;SceneManager.LoadSceneAsync(LoadSceneName);}// 更新public void StateUpdate(){// 是否還在載入if( Application.isLoadingLevel)return ;// 通知新的State開始if( m_State != null && m_bRunBegin==false){m_State.StateBegin();m_bRunBegin = true;}if( m_State != null)m_State.StateUpdate();}}
```csharp public abstract class SceneState { // 状态名称 private string m_StateName = “SceneState”; public string StateName {
get{ return m_StateName; }set{ m_StateName = value; }
} // 状态拥有者 protected SceneStateController m_Controller = null; // 构造 public SceneState(SceneStateController Controller) {
m_Controller = Controller;
} // 开始 public virtual void StateBegin() {} // 結束 public virtual void StateEnd() {} // 更新 public virtual void StateUpdate() {} public override string ToString () {
return string.Format ("[I_SceneState: StateName={0}]", StateName);
}
}
我们在相应的时机更改对应的状态:主菜单中我们添加按钮监听(开始战斗的按钮)-```csharp// 主菜单状态public class MainMenuState : SceneState{public MainMenuState(SceneStateController Controller):base(Controller){//先调用父类Controller为参的构造再把设置父类StateName的值this.StateName = "MainMenuState";}// 开始public override void StateBegin(){// 取得开始按钮Button tmpBtn = UITool.GetUIComponent<Button>("StartGameBtn");if(tmpBtn!=null)tmpBtn.onClick.AddListener( ()=> OnStartGameBtnClick(tmpBtn) );}// 开始战斗private void OnStartGameBtnClick(Button theButton){//Debug.Log ("OnStartBtnClick:"+theButton.gameObject.name);m_Controller.SetState(new BattleState(m_Controller), "BattleScene" );}}
