天天看點

有限狀态機FSM詳解(二)

第一篇寫好了接口,這篇來寫具體實作。

首先是State類,他要實作IState接口:

public class JyState : IState
    {
        public string Name { get { return _name; } }
        public string Tag
        {
            get { return _tag; }
            set { _tag = value; }
        }
        public float Timer { get { return _timer; } }
        public IStateMachine Parent { get { return _parent; } }
        public List<ITransition> Transitions { get { return _transitions; } }

        public JyState(string name)
        {
            _name = name;
            _transitions = new List<ITransition>();
        }

        /// <summary>
        /// 添加狀态轉換
        /// </summary>
        /// <param name="transition"></param>
        public void AddTransition(ITransition transition)
        {
            if(!_transitions.Contains(transition))            
                _transitions.Add(transition);
            else
            {
                // log warining : 該轉換已經存在
            }
            
        }

        /// <summary>
        /// 進入本狀态
        /// </summary>
        /// <param name="prev"></param>
        public virtual void OnEnter(IState prev)
        {
            _timer = 0;
            _index = 0;
            _isWork = true;
        }

        /// <summary>
        /// 離開本狀态
        /// </summary>
        /// <param name="next"></param>
        public virtual void OnExit(IState next)
        {
            _timer = 0;
            _index = 0;
            _isWork = false;
        }

        /// <summary>
        /// 每幀執行
        /// </summary>
        /// <param name="deltaTime"></param>
        public virtual void OnUpdate(float deltaTime)
        {
            if (!_isWork) return;
            _timer += deltaTime;
            if (_transitions.Count < 1) return;
            
            // 如果檢測能夠轉換,則進入轉換函數中
            if (_workingTransition != null && _workingTransition.OnCheck())
            {
                // 如果轉換完成
                if (_workingTransition.OnCompleteCallBack())
                {
                    DoTransition(_workingTransition);
                }
                return;
            }

            _index += 1;
            if (_index >= _transitions.Count) _index = 0;
            _workingTransition = _transitions[_index];
        }

        /// <summary>
        /// 設定本狀态的父狀态機
        /// </summary>
        /// <param name="stateMachine"></param>
        public void SetStateMachine(IStateMachine stateMachine)
        {
            _parent = stateMachine;
        }

        protected string _tag;
        protected string _name;
        protected float _timer;
        protected bool _isWork;
        protected int _index;
        protected IStateMachine _parent;
        protected List<ITransition> _transitions;
        protected ITransition _workingTransition;

        /// <summary>
        /// 執行轉換
        /// </summary>
        /// <param name="transition"></param>
        protected virtual void DoTransition(ITransition transition)
        {
            Parent.CurState.OnExit(transition.ToState);
            Parent.SetCurState(transition.ToState);
            Parent.CurState.OnEnter(transition.FromState);
        }
    }
           

狀态機StateMachine實作IStateMachine接口:

public class JyStateMachine : JyState, IStateMachine
    {
        public IState CurState { get { return _curState; } }
        public IState DefaultState { get { return _defaultState; } }        
        public Dictionary<string, IState> States { get { return _states; } }

        public JyStateMachine(string name, IState defaultState) : base(name)
        {
            _states = new Dictionary<string, IState>();
            AddState(defaultState);
            _defaultState = defaultState;
            _curState = defaultState;
            _curState.OnEnter(null);
        }

        /// <summary>
        /// 添加狀态
        /// </summary>
        /// <param name="state"></param>
        public void AddState(IState state)
        {
            if(!_states.ContainsKey(state.Name))
            {
                _states.Add(state.Name, state);
                state.SetStateMachine(this);
            }
            else
            {
                // log warining: 已有該 state 狀态
            }
        }

        /// <summary>
        /// 獲得狀态
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public IState GetStateWithName(string name)
        {
            return _states != null ? _states[name] : null;
        }

        /// <summary>
        /// 獲得狀态
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        public IState GetStateWithTag(string tag)
        {
            foreach(var state in _states.Values)
            {
                if (state.Tag == tag)
                    return state;
            }
            return null;
        }

        /// <summary>
        /// 移除狀态
        /// </summary>
        /// <param name="state"></param>
        public void RemoveState(IState state)
        {
            if (_states.ContainsKey(state.Name)) _states.Remove(state.Name);
            if (_defaultState == _curState && _curState == state)
            {
                _curState = _states.Count > 0 ? _states[_states.Keys.ToArray()[0]] : null;
                _defaultState = _curState;                
            }
            else if(_defaultState != _curState && _defaultState == state)
            {
                _defaultState = _curState;
            }
            else if(_curState != _defaultState && _curState == state)
            {
                _curState = _states.Count > 0 ? _states[_states.Keys.ToArray()[0]] : null;
            }
        }

        /// <summary>
        /// 設定目前狀态
        /// </summary>
        /// <param name="state"></param>
        public void SetCurState(IState state)
        {
            if(state == null)
            {
                // log warining : 傳入的 state 為空!
                return;
            }

            _curState = state;
        }

        public override void OnEnter(IState prev)
        {
            base.OnEnter(prev);
            _curState.OnEnter(prev);
        }

        public override void OnExit(IState next)
        {
            base.OnExit(next);
            _curState.OnExit(next);
        }

        public override void OnUpdate(float deltaTime)
        {
            base.OnUpdate(deltaTime);
            _curState.OnUpdate(deltaTime);
        }

        private IState _curState;
        private IState _defaultState;
        private Dictionary<string, IState> _states;
    }
           

狀态轉換 StateTransition 實作 IStateTransition接口:

public class JyTransition : ITransition
    {
        public JyTransition(string name, IState from, IState to)
        {
            _to = to;
            _from = from;
            _name = name;
        }

        public string Name { get { return _name; } }
        public IState ToState { get { return _to; } }
        public IState FromState { get { return _from; } }

        /// <summary>
        /// 檢測能否轉換
        /// </summary>
        /// <returns></returns>
        public virtual bool OnCheck()
        {
            return true;
        }

        /// <summary>
        /// 檢測轉換函數是否執行完畢
        /// </summary>
        /// <returns></returns>
        public virtual bool OnCompleteCallBack()
        {
            return true;
        }

        protected IState _from;
        protected IState _to;
        protected string _name;
    }
           

三個關鍵類實作完成後,最後該講如何使用,這裡我們用遊戲角色的  移動、跳躍、攻擊、待機  這四個狀态來做例子講解。

講解放在第三篇。

繼續閱讀