一、状态模式定义
状态模式(state)在GoF中的解释: 让一个对象的行为随着内部状态的改变而改变,而该对象也想换了类一样。
二、实现范例
结构图:
public class Context
{
State state = null;
public void Request(int Value)
{
state.Handle(Value);
}
public void SetState(State state)
{
this.state = state;
}
}
public abstract class State
{
protected Context m_Context = null;
public State(Context context)
{
m_Context = context;
}
public abstract void Handle(int Value);
}
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));
}
}
}
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));
}
}
}
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));
}
}
}
三、使用状态模式(state)实现游戏场景的转换
场景结构示意图:
public class ISceneState
{
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;
}
public virtual void StateBegin() { }
public virtual void StateEnd() { }
public virtual void StateUpdate() { }
public override string ToString()
{
return $"[I_SceneState: StateName={StateName}]";
}
}
- 三个可切换场景(主画面场景,主画面场景,战斗场景)
主画面场景
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");
}
}
主画面场景
public class MainMenuState:ISceneState
{
private Button tmpBtn;
public MainMenuState(SceneStateController controller) : base(controller)
{
this.StateName = "MainMenuState";
}
public override void StateBegin()
{
tmpBtn?.onClick.AddListener(()=>OnStartGameBtnClick(tmpBtn));
}
private void OnStartGameBtnClick(Button tmpBtn)
{
m_Controller.SetState(new BattleState(m_Controller), "BattleScene");
}
}
战斗场景
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()
{
InputProcess();
m_Controller.SetState(new MainMenuState(m_Controller), "MainMenuState");
}
private void InputProcess()
{
}
}
- SceneStateController-场景状态控制者
public class SceneStateController
{
private ISceneState m_State;
private bool m_bRunBegin = false;
public SceneStateController() { }
public void SetState(ISceneState state, string loadSceneName)
{
m_bRunBegin = false;
LoadScene(loadSceneName);
if (m_State != null)
m_State.StateEnd();
m_State = state;
}
private void LoadScene(string loadSceneName)
{
if (string.IsNullOrEmpty(loadSceneName))
{
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();
}
}
}
public class GameLoop:MonoBehaviour
{
SceneStateController sceneStateController = new SceneStateController();
void Awake()
{
GameObject.DontDestroyOnLoad(gameObject);
Random.seed = (int)System.DateTime.Now.Ticks;
}
private void Start()
{
sceneStateController.SetState(new StartState(sceneStateController), "");
}
private void Update()
{
sceneStateController.StateUpdate();
}
}
四、使用状态模式的优点
优点
- 减少错误的发生并降低维护难度;
- 状态执行环境单一化;
- 项目之间可以共享场景;
具体来说,使用状态模式可以清楚地了解某个场景状态执行时所需要配合使用的类对象,并且减少因新增状态而需要大量修改现有程序代码的维护成本。
缺点 在应用有大量状态的系统时,会遇到“产生过多状态类”的情况,此时会伴随着类爆炸的问题。
|