有限状态机的实现

本文介绍了有限状态机在代码设计中的应用,包括其在逻辑管理中的作用、状态切换处理、数据结构(如字典用于快速查找状态)以及关键类如FsmState.cs和FsmMgr.cs的实现,展示了如何使用状态机提高代码效率和组织复杂逻辑。
摘要由CSDN通过智能技术生成

有限状态机的作用:

        有限状态机能够很好的处理大量条件语句的逻辑,使整体的代码逻辑简洁而高效。有限状态机常用于角色控制,ai,流程控制,Ui显示控制等等,应该十分广泛。

代码设计:

        设计思路:

        有限状态机的核心有两点,第一是不同状态之间切换的处理,第二是状态的数据处理。

        对于第一点,当状态需要发生变化时,状态机管理器需要让当前状态退出,新的状态进入。状态机本身是不关注状态切换的条件,只关注状态切换时原状态和新状态的处理。

        对于第二点,需要理解状态机的本质,状态机是逻辑管理的延申,没有状态机同样的逻辑一样能够运行。所以对于状态中获取的数据或者产生的数据都应该是通过状态的持有者里获取或者储存。不要把数据存储在状态本身。

        

        数据结构:

        状态机管理器使用字典管理添加至此状态机的状态,能够快速查找指定的状态即可(O(1))。

        导图:

关键代码:

        FsmState.cs

        状态的基类,提供了状态激活,状态退出,状态更新三个虚函数。并且通过泛型指定状态的持有者。

public class StateBase 
{
 
    public string stateName;

    public StateBase(string stateName)
    {
        this.stateName = stateName;
    }

    public virtual void OnEnterState()
    {
    }

    public virtual void OnExitState()
    {
    }

    public virtual void OnUpdateState()
    {
    }
}



public class FsmState<T> : StateBase
{
    public T owner;

    public FsmState(string stateName, T owner) : base(stateName)
    {
        this.owner = owner;
    }
}

        FsmMgr.cs

        状态机管理器,管理状态之间的相互切换。并且支持状态集

public class FsmMgr 
{
    private Dictionary<string, StateBase> _fsmStateDic = new Dictionary<string, StateBase>();
    private Dictionary<string, List<StateEvent>> _fsmStateEventDic = new Dictionary<string, List<StateEvent>>();


    private float _stateStartTime;
    private float stateTime
    {
        get
        {
            return Time.time - _stateStartTime;
        }
    }

    public FsmMgr()
    {
        _stateStartTime = 0;
    }

    private string _preStateName;
    private string _curStateName;
    public string curStateName
    {
        get
        {
            return _curStateName;
        }
        set
        {
            if (_preStateName != null)
            {
                OnExitState(_preStateName);
            }
            _preStateName = _curStateName;
            _curStateName = value;
            _stateStartTime = Time.time;
            OnEnterState(_curStateName);
        }
    }


    private void OnExitState(string stateName)
    {
        if (_fsmStateDic.ContainsKey(stateName))
        {
            _fsmStateDic[stateName].OnExitState();
        }
    }


    private void OnEnterState(string stateName)
    {
        if (_fsmStateDic.ContainsKey(stateName))
        {
            _fsmStateDic[stateName].OnEnterState();
        }
    }

    public void OnUpdateState()
    {
        if (_fsmStateDic.ContainsKey(_curStateName))
        {
            _fsmStateDic[_curStateName].OnUpdateState();
        }
    }


    public void ChangeState(string stateName)
    {
        if (!EqualityComparer<string>.Default.Equals(curStateName, stateName))
        {
            curStateName = stateName;
        }
    }

    public void AddState(StateBase fsm)
    {
        if (!_fsmStateDic.ContainsKey(fsm.stateName))
        {
            _fsmStateDic.Add(fsm.stateName, fsm);

        }
    }



    public void SendFsmStateEvent(string fsmEventKey)
    {
        if (_fsmStateEventDic.ContainsKey(fsmEventKey))
        {
            _fsmStateEventDic.TryGetValue(fsmEventKey, out List<StateEvent> stateEvents);
            foreach (StateEvent stateEvent in stateEvents)
            {
                if (_curStateName == stateEvent.fromState)
                {
                    ChangeState(stateEvent.toState);
                }
            }

        }
    }


    public void RegisterFsmStateEvent(string fsmEventKey, string fromState, string toState)
    {
        if (!_fsmStateEventDic.ContainsKey(fsmEventKey))
        {
            List<StateEvent> stateEvents = new List<StateEvent>();
            StateEvent stateEvent = new StateEvent();
            stateEvent.fromState = fromState;
            stateEvent.toState = toState;
            stateEvents.Add(stateEvent);
            _fsmStateEventDic.Add(fsmEventKey, stateEvents);
        }
        else
        {
            _fsmStateEventDic.TryGetValue(fsmEventKey, out List<StateEvent> stateEvents);
            if (stateEvents != null)
            {
                StateEvent stateEvent = new StateEvent();
                stateEvent.fromState = fromState;
                stateEvent.toState = toState;
                stateEvents.Add(stateEvent);
            }
        }
    }


    
}



public class StateEvent
{
    public string fromState;
    public string toState;
}

    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值