状态模式

  • 角色状态
  • AI状态
  • 账号登陆状态
  • 场景状态
  • 动画机状态

1.简单的状态控制
https://www.youtube.com/watch?v=r-RCfmQqLA0
(作者本意为避免if嵌套,避免定义过多变量进行开关控制)
有人指出这不是一个好办法,因为在添加状态时要不断为新状态创建新的类,一个方法占据一个单独的类,过多的类反而使管理和可读性变差。
状态管理利用字典返回一个状态标志。

  1. class Character:MonoBenaviour
  2. {
  3. characterState state;
  4. void Update()
  5. {
  6. state = state.handleInput();
  7. }
  8. }
  1. class characterState
  2. {
  3. virtual public characterState handleInput(){return this;}
  4. }
  5. class JumpingState:characterState
  6. {
  7. override public characterState handleInput(){return this;}
  8. }
  9. class IdleState:characterState
  10. {
  11. override public characterState handleInput()
  12. {
  13. if(按下跳跃键)
  14. return new JumpingState();
  15. return this;
  16. }
  17. }

2.场景执行用状态管理
https://zhuanlan.zhihu.com/p/85095810
和上个部分类似,说明更详细一些
以场景的转换作为示例展示状态模式

  • GameLoop:游戏的主循环,继承自MonoBehavior,包含了游戏的初始化和循环更新操作,同时也是设置起始场景的地方。
  • SceneStateController:场景状态的拥有者,对应上面说的Context(状态拥有者),执行场景转换的地方,在GameLoop中完成创建。
  • SceneState:场景的抽象类,定义了场景转换和执行时所需的方法。
  • StartState、MainMenuState、BattleState:分别对应了开始场景、主界面场景、战斗场景的具体实现类。

    1. public class GameLoop : MonoBehaviour
    2. {
    3. // 场景状态持有者
    4. SceneStateController m_SceneStateController = new SceneStateController();
    5. //
    6. void Awake()
    7. {
    8. // 保证场景切换时不会被删除
    9. GameObject.DontDestroyOnLoad( this.gameObject );
    10. }
    11. // Use this for initialization
    12. void Start ()
    13. {
    14. // 设定起始场景
    15. m_SceneStateController.SetState(new StartState(m_SceneStateController), "");
    16. }
    17. // Update is called once per frame
    18. void Update ()
    19. {
    20. m_SceneStateController.StateUpdate();
    21. }
    22. }
    1. public class SceneStateController
    2. {
    3. private SceneState m_State;
    4. private bool m_bRunBegin = false;
    5. public SceneStateController()
    6. {}
    7. // 设定状态
    8. public void SetState(SceneState State, string LoadSceneName)
    9. {
    10. //Debug.Log ("SetState:"+State.ToString());
    11. m_bRunBegin = false;
    12. // 载入场景
    13. LoadScene(LoadSceneName);
    14. // 通知前一个State結束
    15. if( m_State != null )
    16. m_State.StateEnd();
    17. // 设定
    18. m_State=State;
    19. }
    20. // 载入
    21. private void LoadScene(string LoadSceneName)
    22. {
    23. if( LoadSceneName==null || LoadSceneName.Length == 0 )
    24. return ;
    25. SceneManager.LoadSceneAsync(LoadSceneName);
    26. }
    27. // 更新
    28. public void StateUpdate()
    29. {
    30. // 是否還在載入
    31. if( Application.isLoadingLevel)
    32. return ;
    33. // 通知新的State開始
    34. if( m_State != null && m_bRunBegin==false)
    35. {
    36. m_State.StateBegin();
    37. m_bRunBegin = true;
    38. }
    39. if( m_State != null)
    40. m_State.StateUpdate();
    41. }
    42. }

    ```csharp public abstract class SceneState { // 状态名称 private string m_StateName = “SceneState”; public string StateName {

    1. get{ return m_StateName; }
    2. set{ m_StateName = value; }

    } // 状态拥有者 protected SceneStateController m_Controller = null; // 构造 public SceneState(SceneStateController Controller) {

    1. m_Controller = Controller;

    } // 开始 public virtual void StateBegin() {} // 結束 public virtual void StateEnd() {} // 更新 public virtual void StateUpdate() {} public override string ToString () {

    1. return string.Format ("[I_SceneState: StateName={0}]", StateName);

    }

}

  1. 我们在相应的时机更改对应的状态:主菜单中我们添加按钮监听(开始战斗的按钮)-
  2. ```csharp
  3. // 主菜单状态
  4. public class MainMenuState : SceneState
  5. {
  6. public MainMenuState(SceneStateController Controller):base(Controller)
  7. {
  8. //先调用父类Controller为参的构造再把设置父类StateName的值
  9. this.StateName = "MainMenuState";
  10. }
  11. // 开始
  12. public override void StateBegin()
  13. {
  14. // 取得开始按钮
  15. Button tmpBtn = UITool.GetUIComponent<Button>("StartGameBtn");
  16. if(tmpBtn!=null)
  17. tmpBtn.onClick.AddListener( ()=> OnStartGameBtnClick(tmpBtn) );
  18. }
  19. // 开始战斗
  20. private void OnStartGameBtnClick(Button theButton)
  21. {
  22. //Debug.Log ("OnStartBtnClick:"+theButton.gameObject.name);
  23. m_Controller.SetState(new BattleState(m_Controller), "BattleScene" );
  24. }
  25. }