状态模式的定义及其简单的游戏应用
状态模式(State)
定义
Context:状态拥有者,制定接口让外界改变状态或者得知状态已经改变。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class Context { State m_state = null; public void Request(int Value) { m_state.Handle(Value); }
public void SetState(State theState) { Debug.Log("Context.SetState:" + theState); m_state = theState; } }
|
State:状态接口,负责规范Context在特定状态下要表现的行为
1 2 3 4 5 6 7 8 9 10 11
| public abstract class State { protected Context m_Context = null; public State(Context theContext) { m_Context = theContext; } public abstract void Handle(int value); }
|
ConcreteState:具体状态,继承State,实现具体状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class ConcreteStateA : State { public ConcreteStateA(Context theContext) : base(theContext) { }
public override void Handle(int Value) { Debug.Log("ConcreteStateA.Handle"); if (Value > 10) m_Context.SetState(new ConcreteStateB(m_Context)); } } public class ConcreteStateB : State { public ConcreteStateB(Context theContext) : base(theContext) { }
public override void Handle(int Value) { Debug.Log("ConcreteStateB.Handle"); if (Value > 20) m_Context.SetState(new ConcreteStateC(m_Context)); } } public class ConcreteStateC : State { public ConcreteStateC(Context theContext) : base(theContext) { }
public override void Handle(int Value) { Debug.Log("ConcreteStateC.Handle"); if (Value > 30) m_Context.SetState(new ConcreteStateA(m_Context)); } }
|
游戏应用:简单实现场景切换
场景控制:Context
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI;
public class SceneStateController { private ISceneState m_State; private bool m_bRunBegin = false; public SceneStateController() { }
public void SetState(ISceneState State,string LoadSceneName) { Debug.Log("SetState:" + State.ToString()); m_bRunBegin = false;
LoadScene(LoadSceneName);
if (m_State != null) m_State.StateEnd();
m_State = State;
} private void LoadScene(string LoadSceneName) { if (LoadSceneName == null || LoadSceneName.Length == 0) return; SceneManager.LoadScene(LoadSceneName);
}
public void StateUpdate() { if (m_State != null && m_bRunBegin == false) { m_State.StateBegin(); m_bRunBegin = true; }
if (m_State != null) m_State.StateUpdate(); } }
|
场景接口:State
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| using System.Collections; using System.Collections.Generic; using UnityEngine;
public class ISceneState { private string m_StateName = "ISceneState"; public string StateName { get { return m_StateName; } set { m_StateName = value; } }
protected SceneStateController m_Controller = null;
public ISceneState(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); }
}
|
具体场景实现
开始场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| using System.Collections; using System.Collections.Generic; using UnityEngine;
public class StartState : ISceneState { public StartState(SceneStateController Controller):base(Controller) { this.StateName = "StartState"; }
public override void StateBegin() {
}
public override void StateUpdate() { m_Controller.SetState(new MainMenuState(m_Controller), "MainMenuScene"); } }
|
主菜单场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| using UnityEngine; using UnityEngine.UI;
public class MainMenuState : ISceneState { public MainMenuState(SceneStateController Controller) : base(Controller) { this.StateName = "MainMenuState"; }
public override void StateBegin() { }
public override void StateUpdate() { if (Input.GetKeyDown(KeyCode.B)) { m_Controller.SetState(new BattleState(m_Controller), "BattleScene"); } } }
|
战斗场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| using UnityEngine;
public class BattleState : ISceneState { public BattleState(SceneStateController Controller) : base(Controller) { this.StateName = "BattleState"; }
public override void StateBegin() { }
public override void StateEnd() { }
public override void StateUpdate() { if (Input.GetKeyDown(KeyCode.Space)) { m_Controller.SetState(new MainMenuState(m_Controller), "MainMenuScene"); } }
}
|
GameLoop
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| using System; using System.Collections; using System.Collections.Generic; using UnityEngine;
public class GameLoop : MonoBehaviour { SceneStateController m_SceneStateController = new SceneStateController();
private void Awake() { GameObject.DontDestroyOnLoad(this.gameObject);
UnityEngine.Random.InitState((int)DateTime.Now.Ticks); }
private void Start() { m_SceneStateController.SetState(new StartState(m_SceneStateController), ""); }
private void Update() { m_SceneStateController.StateUpdate(); } }
|
个人理解
context是状态和外部的连接,状态的控制器,设置(改变)状态在这里面,里面有一个state类的实体,用来保存当前存在的状态。外部通过context来改变状态。
state是具体状态的父类,规范状态要做什么,以及引用了控制器实体。
具体状态通过控制器里面的函数切换状态,切换各个状态的具体条件也写在这里面,通过引用控制器实体里的函数来转换当前存在的状态。