State mode (State)
1. Definition of state mode
Explanation of the state pattern in GoF:
Let the behavior of an object change with the change of the internal state, and the object also wants to change the class.
2. Implementation example
Structure diagram:
- Context (state owner)
/// <summary>
/// Author:maki
/// Time:2021-12-2
/// Describe:状态拥有者
/// Note:是一个具有“状态”属性的类,可以制定相关的接口,让外界能够得知状态的改变或通过操作让状态改变。
/// 比如:游戏角色有潜行,攻击、施法等状态;好友上线,脱机、忙碌等状态;
/// GoF使用TCP联网为例,有已连接、等待连接、短线等状态;
/// </summary>
public class Context
{
State state = null;
public void Request(int Value)
{
state.Handle(Value);
}
public void SetState(State state)
{
this.state = state;
}
}
- State (state interface class)
/// <summary>
/// Author:maki
/// Time:2021-12-2
/// Describe:状态接口类
/// Note:指定状态的接口,负责规范Context(状态拥有者)在特定状态下要表现的行为。
/// </summary>
public abstract class State
{
protected Context m_Context = null;
public State(Context context)
{
m_Context = context;
}
public abstract void Handle(int Value);
}
- ConcreteState (concrete state class)
/*
Author:maki
Time:2021-12-2
Describe:具体状态类
Note:
1、继承自State(状态接口类)
2、实现Context(状态拥有者)在特定状态下该有的行为。
*/
//状态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));
}
}
}
//状态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));
}
}
}
//状态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));
}
}
}
Third, use the state mode (state) to realize the conversion of the game scene
Schematic diagram of the scene structure:
- ISceneState scene class interface
/// <summary>
/// Author:maki
/// Time:2021-12-2
/// Describe:场景类接口
/// Note:定义场景转换和执行时需要调用的方法。
/// </summary>
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}]";
}
}
- Three switchable scenes (main screen scene, main screen scene, battle scene)
main screen scene
/// <summary>
/// Author:maki
/// Time:2021-12-2
/// Describe:开始场景
/// </summary>
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");
}
}
main screen scene
/// <summary>
/// Author:maki
/// Time:2021-12-2
/// Describe:主画面场景
/// </summary>
public class MainMenuState:ISceneState
{
private Button tmpBtn;
public MainMenuState(SceneStateController controller) : base(controller)
{
this.StateName = "MainMenuState";
}
//开始
public override void StateBegin()
{
//获取开始按钮
// tmpBtn=UITool.GetUIComponent<Button>("StartGameBtn");
tmpBtn?.onClick.AddListener(()=>OnStartGameBtnClick(tmpBtn));
}
//开始游戏
private void OnStartGameBtnClick(Button tmpBtn)
{
m_Controller.SetState(new BattleState(m_Controller), "BattleScene");
}
}
battle scene
/// <summary>
/// Author:maki
/// Time:2021-12-2
/// Describe:战斗场景
/// </summary>
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 - scene state controller
/// <summary>
/// Author:maki
/// Time:2021-12-2
/// Describe:场景状态的拥有者(Context),保持当前游戏场景状态,并作为与GameLoop类互动的接口,
/// 除此以外,也是U3D场景转换的地方。
/// </summary>
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);
//通知前一个State结束
if (m_State != null)
m_State.StateEnd();
//设置
m_State = state;
}
//载入场景
private void LoadScene(string loadSceneName)
{
if (string.IsNullOrEmpty(loadSceneName))
{
return;
}
SceneManager.LoadScene(loadSceneName);
// Application.LoadLevel(loadSceneName); 过时
}
//更新
public void StateUpdate()
{
//通知新的State开始
if (m_State != null && m_bRunBegin == false)
{
m_State.StateBegin();
m_bRunBegin = true;
}
if (m_State != null)
{
m_State.StateUpdate();
}
}
}
- GameLoop - game main loop class
/// <summary>
/// Author:maki
/// Time:2021-12-2
/// Describe:游戏主循环类
/// Note:包含初始化游戏和定期调用更新操作
/// </summary>
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();
}
}
Fourth, the advantages of using the state mode
advantage
- Reduce the occurrence of errors and reduce maintenance difficulty;
- State execution environment simplification;
- Scenes can be shared between projects;
Specifically, using the state pattern can clearly understand the class objects that need to be used with the execution of a scene state, and reduce the maintenance cost of a large number of modifications to the existing program code due to the new state.
Disadvantages
When applying a system with a large number of states, you will encounter the situation of " generating too many state classes ", which will be accompanied by the problem of class explosion.