Unity:状态模式与状态机

 一些玩家或者物体的状态可以用状态机来实现,而状态机一般由状态模式这个思想去实现。

大致思路:

Controller:管理器来管理状态的生命周期

Data:用字典来储存状态,以及储存当前的状态(比如说创建,以及删除状态)

Factroy:状态工厂

Satat:具体状态

Config:用枚举类型来表示所有的状态,并且用枚举类型来判断一个状态时候可以转换(当添加新状态时,只需再在枚举类型里面注册即可)

Controller脚本:

public class PlayerStateController : MonoBehaviour
    {
        
        protected Dictionary<PlayerState, PlayerBaseState> statesDic;
        protected PlayerStateData stateData;
        protected PlayerStateFactory stateFactory;
        public PlayerBaseState currentState;
        
        
        protected void Awake()
        {
            Create();
            Init();
        }

        protected void Create()
        {
            stateFactory = new PlayerStateFactory();
            stateData = new PlayerStateData();
        }

        protected void Init()
        {
            stateFactory.Init(stateData);
            stateData.Init(stateFactory);
            
            statesDic = stateData.GetStateDic();
            currentState = stateData.GetCurrentState();
        }
        
        protected void Update()
        {
            currentState.UpdateState();
        }

        public void ChanageState()
        {
            
        }
    }

Data:

public class PlayerStateData
    {
        protected Dictionary<PlayerState, PlayerBaseState> statesDic = new Dictionary<PlayerState, PlayerBaseState>();
        protected PlayerState currentStateEnum;
        protected PlayerStateFactory stateFactory;

        public PlayerStateData()
        {
            currentStateEnum = PlayerState.Idle;
        }

        public void Init(PlayerStateFactory factory)
        {
            stateFactory = factory;
            CreateNewState(currentStateEnum);
        }
        
        public Dictionary <PlayerState, PlayerBaseState> GetStateDic()
        {
            return statesDic;
        }

        public void AddState(PlayerState stateEnum, PlayerBaseState state)
        {
            if (statesDic.ContainsKey(stateEnum))
                return;
            statesDic.Add(stateEnum, state);
        }

        public void RemoveState(PlayerState stateEnum)
        {
            if (!statesDic.ContainsKey(stateEnum))
                return;
            statesDic.Remove(stateEnum);
        }

        public PlayerBaseState GetCurrentState()
        {
            return statesDic[currentStateEnum];
        }

        public PlayerBaseState SetCurrentState(PlayerState state)
        { 
            currentStateEnum = state;
            return statesDic[currentStateEnum];
        }
        
        public void CreateNewState(PlayerState newStateEnum)
        {
            if (statesDic.ContainsKey(newStateEnum))
                return;
            PlayerBaseState state = stateFactory.CreateState(newStateEnum);
            AddState(newStateEnum, state);
        }
    }

Factroy:

public class PlayerStateFactory 
    {
        private PlayerStateData _stateData;

        public void Init(PlayerStateData data)
        {
            _stateData = data;
        }

        public PlayerBaseState CreateState(PlayerState stateEnum)
        {
            switch (stateEnum)
            {
                case PlayerState.Idle:
                    return new PlayerIdleState(stateEnum, _stateData);
                case PlayerState.Run:
                    return new PlayerRunState(stateEnum, _stateData);
                case PlayerState.Walk:
                    return new PlayerWalkState(stateEnum, _stateData);
                default:
                    throw new ArgumentOutOfRangeException(nameof(stateEnum), stateEnum, "Invalid state type");
            }
        }
    }

StateBase:

 public class PlayerBaseState
    {
        protected PlayerState playerStateEnum;
        protected Dictionary<PlayerState, PlayerBaseState> statesDic;
        protected PlayerStateData stateData;
        protected PlayerIdleStateChange[] validIdleStateChanges =
            (PlayerIdleStateChange[])Enum.GetValues(typeof(PlayerIdleStateChange));

        public PlayerBaseState(PlayerState stateEnum , PlayerStateData data )
        {
            playerStateEnum = stateEnum;
            stateData = data;
            statesDic = stateData.GetStateDic();
        }

    public virtual void OnEnterState()
    {
        stateData.SetCurrentState(playerStateEnum);
    }

        public  virtual void UpdateState()
        {
        }

        public  virtual void OnExitState()
        {
        }

        public  virtual void ChangeState(PlayerState newStateEnum)
        {
            if( !IsChangeState(newStateEnum))
                return;
            if (!statesDic.ContainsKey(newStateEnum))
                stateData.CreateNewState(newStateEnum);
            OnExitState();
            statesDic[newStateEnum].OnEnterState();
        }
        public virtual bool IsChangeState(PlayerState newStateEnum)
        {
            return false;
        }
    }

State:

 public PlayerIdleState(PlayerState stateEnum , PlayerStateData data) : base(stateEnum, data)
        {
          
        }

        public override void UpdateState()
        {
            Debug.Log("物体处于 Idel状态");
        }

        public  override void ChangeState(PlayerState newState)
        {
            base.ChangeState(newState);
        }

        public override bool IsChangeState(PlayerState newState)
        {
            foreach (PlayerIdleStateChange state in validIdleStateChanges)
            {
                if((int)newState == (int) state)
                    return true;
            }
            return false;
        }
    }

Config:

public enum PlayerState
    {
        Idle = 1, 
        Run = 2,
        Walk = 3,
    }

    public enum PlayerIdleStateChange
    {
        Run = 2,
        Walk = 3
    }
    
    public enum PlayerRunStateChange
    {
        Idle = 1,
        Walk = 3,
    }
    
    public enum PlayerWalkStateChange
    {
        Idle = 1,
        Run = 2,
    }

    public class PlayerConfig
    {
    }