Unity Game Design Patterns - State Pattern

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:
insert image description here

  • 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:
insert image description here

  • 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.

Guess you like

Origin blog.csdn.net/qq_40120946/article/details/121688437