C# Unity FSM 状态机
使用状态机可以降低代码耦合性,并且可以优化代码可读性,方便团队协作等。
对于游戏开发内容来讲游戏开发的流程控制玩家动画都可以使用FSM有限状态机来实现。
1.FsmState
每个状态的基类,泛型参数表示所拥有者
csharp
public abstract class FsmState<T> where T : class
{
protected internal abstract void OnInit(IFsm<T> fsm);
protected internal abstract void OnEnter(IFsm<T> fsm);
protected internal abstract void OnUpdate(IFsm<T> fsm);
protected internal abstract void OnLeave(IFsm<T> fsm);
protected internal abstract void OnDestroy(IFsm<T> fsm);
protected void ChangeState<TState>(IFsm<T> fsm) where TState : FsmState<T>
{
Fsm<T> fsmImplement = (Fsm<T>)fsm;
if(fsmImplement == null)
{
throw new Exception("FSM is invalid.");
}
fsmImplement.ChangeState<TState>();
}
protected void ChangeState(IFsm<T> fsm, Type stateType)
{
Fsm<T> fsmImplement = (Fsm<T>)fsm;
if (fsmImplement == null)
{
throw new Exception("FSM is invalid.");
}
if (stateType == null)
{
throw new Exception("State type is invalid.");
}
if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
{
throw new Exception("State type is invalid.");
}
fsmImplement.ChangeState(stateType);
}
}
2.IFsm
有限状态机的接口
csharp
public interface IFsm<T> where T : class
{
string Name
{
get;
}
string FullName
{
get;
}
T Owner
{
get;
}
int FsmStateCount
{
get;
}
bool IsRunning
{
get;
}
bool IsDestroyed
{
get;
}
FsmState<T> CurrentState
{
get;
}
float CurrentStateTime
{
get;
}
void Start<TState>() where TState : FsmState<T>;
bool HasState<TState>() where TState : FsmState<T>;
TState GetState<TState>() where TState : FsmState<T>;
FsmState<T> GetState(Type stateType);
FsmState<T>[] GetAllStates();
}
3.IFsmManager
有限状态机管理器接口
csharp
public interface IFsmManager
{
int Count { get; }
bool HasFsm<T>() where T : class;
bool HasFsm(Type ownerType);
bool HasFsm<T>(string name) where T : class;
bool HasFsm(Type ownerType, string name);
IFsm<T> GetFsm<T>() where T : class;
IFsm<T> GetFsm<T>(string name) where T : class;
IFsm<T> CreateFsm<T>(T owner, params FsmState<T>[] fsmStates) where T : class;
IFsm<T> CreateFsm<T>(string name, T owner, params FsmState<T>[] states) where T : class;
IFsm<T> CreateFsm<T>(T owner, List<FsmState<T>> states) where T : class;
IFsm<T> CreateFsm<T>(string name, T owner, List<FsmState<T>> states) where T : class;
bool DestroyFsm<T>() where T : class;
bool DestroyFsm(Type ownerType);
bool DestroyFsm<T>(string name) where T : class;
bool DestroyFsm(Type ownerType, string name);
bool DestroyFsm<T>(IFsm<T> fsm) where T : class;
}
4.FsmBase
有限状态机的基类
csharp
public abstract class FsmBase
{
private string m_Name;
public FsmBase()
{
m_Name = string.Empty;
}
public string Name
{
get
{
return m_Name;
}
protected set
{
m_Name = value ?? string.Empty;
}
}
public string FullName
{
get
{
return $"{OwnerType.FullName}.{Name}";
}
}
public abstract Type OwnerType
{
get;
}
public abstract int FsmStateCount
{
get;
}
public abstract bool IsRunning
{
get;
}
public abstract bool IsDestroyed
{
get;
}
public abstract string CurrentStateName
{
get;
}
public abstract float CurrentStateTime
{
get;
}
public abstract void Update();
public abstract void Shutdown();
}
5.Fsm
状态机类
csharp
public class Fsm<T> : FsmBase, IFsm<T> where T : class
{
private T m_Owner;
private readonly Dictionary<Type, FsmState<T>> m_States;
private FsmState<T> m_CurrentState;
private float m_CurrentStateTime;
private bool m_IsDestroyed;
public Fsm()
{
m_Owner = null;
m_States = new Dictionary<Type, FsmState<T>>();
m_CurrentState = null;
m_CurrentStateTime = 0f;
m_IsDestroyed = true;
}
public T Owner => m_Owner;
public FsmState<T> CurrentState => m_CurrentState;
public override Type OwnerType => typeof(T);
public override int FsmStateCount => m_States.Count;
public override bool IsRunning => m_CurrentState != null;
public override bool IsDestroyed => m_IsDestroyed;
public override string CurrentStateName => m_CurrentState != null ? m_CurrentState.GetType().FullName : null;
public override float CurrentStateTime => m_CurrentStateTime;
public static Fsm<T> Create(string name,T owner,params FsmState<T>[] states)
{
if(owner == null)
{
throw new Exception("FSM owner is invalid.");
}
if(states== null|| states.Length < 1)
{
throw new Exception("FSM states is invalid.");
}
Fsm<T> fsm = Pool<Fsm<T>>.Rent();
fsm.Name = name;
fsm.m_Owner = owner;
fsm.m_IsDestroyed = false;
foreach (FsmState<T> oneState in states)
{
if(oneState == null)
{
throw new Exception("FSM states is invalid.");
}
Type stateType = oneState.GetType();
if (fsm.m_States.ContainsKey(stateType))
{
throw new Exception($"{stateType} state is already exist");
}
fsm.m_States.Add(stateType, oneState);
oneState.OnInit(fsm);
}
return fsm;
}
public static Fsm<T> Create(string name,T owner,List<FsmState<T>> states)
{
if (owner == null)
{
throw new Exception("FSM owner is invalid.");
}
if (states == null || states.Count < 1)
{
throw new Exception("FSM states is invalid.");
}
Fsm<T> fsm = Pool<Fsm<T>>.Rent();
fsm.Name = name;
fsm.m_Owner = owner;
fsm.m_IsDestroyed = false;
foreach (FsmState<T> oneState in states)
{
if (oneState == null)
{
throw new Exception("FSM states is invalid.");
}
Type stateType = oneState.GetType();
if (fsm.m_States.ContainsKey(stateType))
{
throw new Exception($"{stateType} state is already exist");
}
fsm.m_States.Add(stateType, oneState);
oneState.OnInit(fsm);
}
return fsm;
}
public FsmState<T>[] GetAllStates()
{
int index = 0;
FsmState<T>[] arr = new FsmState<T>[m_States.Count];
foreach (FsmState<T> fsmState in m_States.Values)
{
arr[index++] = fsmState;
}
return arr;
}
public bool HasState<TState>() where TState : FsmState<T>
{
return m_States.ContainsKey(typeof(TState));
}
public override void Shutdown()
{
Pool<Fsm<T>>.Return(this, (fsm) =>
{
if(m_CurrentState != null)
{
m_CurrentState.OnLeave(this);
}
foreach (FsmState<T> oneState in m_States.Values)
{
oneState.OnDestroy(this);
}
Name = null;
m_Owner = null;
m_States.Clear();
m_CurrentState = null;
m_CurrentStateTime = 0f;
m_IsDestroyed = true;
});
}
public void Start<TState>() where TState : FsmState<T>
{
if (IsRunning)
{
throw new Exception("FSM is running, can not start again.");
}
FsmState<T> state = GetState<TState>();
if (state == null)
{
throw new Exception("can not start state");
}
m_CurrentStateTime = 0f;
m_CurrentState = state;
m_CurrentState.OnEnter(this);
}
public void Start(Type stateType)
{
if (IsRunning)
{
throw new Exception("FSM is running, can not start again.");
}
if (stateType == null)
{
throw new Exception("State type is invalid.");
}
if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
{
throw new Exception("State type is invalid.");
}
FsmState<T> state = GetState(stateType);
if (state == null)
{
throw new Exception("FSM can not start state which is not exist.");
}
m_CurrentStateTime = 0f;
m_CurrentState = state;
m_CurrentState.OnEnter(this);
}
public override void Update()
{
m_CurrentStateTime += Time.deltaTime;
m_CurrentState.OnUpdate(this);
}
public TState GetState<TState>() where TState : FsmState<T>
{
if (m_States.TryGetValue(typeof(TState), out FsmState<T> fsmState))
{
return (TState)fsmState;
}
return null;
}
public FsmState<T> GetState(Type stateType)
{
if (stateType == null)
{
throw new Exception("State type is invalid.");
}
if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
{
throw new Exception("State type is invalid.");
}
if (m_States.TryGetValue(stateType, out FsmState<T> fsmState))
{
return fsmState;
}
return null;
}
public void ChangeState<TState>()
{
ChangeState(typeof(TState));
}
public void ChangeState(Type stateType)
{
if (m_CurrentState == null)
{
throw new Exception("Current state is invalid.");
}
FsmState<T> state = GetState(stateType);
if (state == null)
{
throw new Exception("FSM can not change state which is not exist.");
}
m_CurrentState.OnLeave(this);
m_CurrentStateTime = 0f;
m_CurrentState = state;
m_CurrentState.OnEnter(this);
}
}
6.FsmManager
状态机管理器
csharp
public class FsmManager : Singleton<FsmManager>,IFsmManager,IUpdateSingleton
{
private readonly Dictionary<string, FsmBase> m_FsmDic;
private readonly List<FsmBase> m_TempFsms;
public FsmManager()
{
m_FsmDic = new Dictionary<string, FsmBase>();
m_TempFsms = new List<FsmBase>();
}
public int Count => m_FsmDic.Count;
public IFsm<T> CreateFsm<T>(T owner, params FsmState<T>[] fsmStates) where T : class
{
return CreateFsm(string.Empty, owner, fsmStates);
}
public IFsm<T> CreateFsm<T>(string name, T owner, params FsmState<T>[] states) where T : class
{
if (HasFsm<T>(name))
{
throw new Exception("Already exist FSM");
}
Fsm<T> fsm = Fsm<T>.Create(name, owner, states);
m_FsmDic.Add(fsm.FullName, fsm);
return fsm;
}
public IFsm<T> CreateFsm<T>(T owner, List<FsmState<T>> states) where T : class
{
return CreateFsm(string.Empty, owner, states);
}
public IFsm<T> CreateFsm<T>(string name, T owner, List<FsmState<T>> states) where T : class
{
if (HasFsm<T>(name))
{
throw new Exception("Already exist FSM");
}
Fsm<T> fsm = Fsm<T>.Create(name, owner, states);
m_FsmDic.Add(fsm.FullName, fsm);
return fsm;
}
public bool DestroyFsm<T>() where T : class
{
return InternalDestroyFsm($"{typeof(T).FullName}.{string.Empty}");
}
public bool DestroyFsm(Type ownerType)
{
if (ownerType == null)
{
throw new Exception("Owner type is invalid.");
}
return InternalDestroyFsm($"{ownerType.FullName}.{string.Empty}");
}
public bool DestroyFsm<T>(string name) where T : class
{
return InternalDestroyFsm($"{typeof(T).FullName}.{name}");
}
public bool DestroyFsm(Type ownerType, string name)
{
if (ownerType == null)
{
throw new Exception("Owner type is invalid.");
}
return InternalDestroyFsm($"{ownerType.FullName}.{name}");
}
public bool DestroyFsm<T>(IFsm<T> fsm) where T : class
{
if (fsm == null)
{
throw new Exception("FSM is invalid.");
}
return InternalDestroyFsm(fsm.FullName);
}
public IFsm<T> GetFsm<T>() where T : class
{
return (IFsm<T>)InternalGetFsm($"{typeof(T).FullName}.{string.Empty}");
}
public IFsm<T> GetFsm<T>(string name) where T : class
{
return (IFsm<T>)InternalGetFsm($"{typeof(T).FullName}.{name}");
}
public bool HasFsm<T>() where T : class
{
return InternalHasFsm($"{typeof(T).FullName}.{string.Empty}");
}
public bool HasFsm(Type ownerType)
{
if(ownerType == null)
{
throw new Exception("Owner type is invalid.");
}
return InternalHasFsm($"{ownerType.FullName}.{string.Empty}");
}
public bool HasFsm<T>(string name) where T : class
{
return InternalHasFsm($"{typeof(T).FullName}.{name}");
}
public bool HasFsm(Type ownerType, string name)
{
if (ownerType == null)
{
throw new Exception("Owner type is invalid.");
}
return InternalHasFsm($"{ownerType.FullName}.{name}");
}
private bool InternalDestroyFsm(string name)
{
if(m_FsmDic.TryGetValue(name,out FsmBase fsmBase))
{
fsmBase.Shutdown();
return m_FsmDic.Remove(name);
}
return false;
}
private FsmBase InternalGetFsm(string name)
{
FsmBase fsm = null;
if (m_FsmDic.TryGetValue(name, out fsm))
{
return fsm;
}
return null;
}
private bool InternalHasFsm(string name)
{
return m_FsmDic.ContainsKey(name);
}
public void Update()
{
m_TempFsms.Clear();
if (m_FsmDic.Count <= 0)
return;
foreach (FsmBase fsmBase in m_FsmDic.Values)
{
m_TempFsms.Add(fsmBase);
}
foreach (FsmBase fsmBase in m_TempFsms)
{
if (fsmBase.IsDestroyed)
continue;
fsmBase.Update();
}
}
protected override void Load(int assemblyName)
{
}
protected override void UnLoad(int assemblyName)
{
}
}
7.测试
(一)IdleState
csharp
public class IdleState : FsmState<FsmTest>
{
protected internal override void OnDestroy(IFsm<FsmTest> fsm)
{
Debug.Log("销毁 IdleState");
}
protected internal override void OnEnter(IFsm<FsmTest> fsm)
{
Debug.Log("进入 IdleState");
}
protected internal override void OnInit(IFsm<FsmTest> fsm)
{
}
protected internal override void OnLeave(IFsm<FsmTest> fsm)
{
Debug.Log("离开 IdleState");
}
protected internal override void OnUpdate(IFsm<FsmTest> fsm)
{
if (Input.GetKeyDown(KeyCode.A))
{
ChangeState<WalkState>(fsm);
}
}
}
(二)WalkState
csharp
public class WalkState : FsmState<FsmTest>
{
protected internal override void OnDestroy(IFsm<FsmTest> fsm)
{
Debug.Log("销毁 WalkState");
}
protected internal override void OnEnter(IFsm<FsmTest> fsm)
{
Debug.Log("进入 WalkState");
}
protected internal override void OnInit(IFsm<FsmTest> fsm)
{
}
protected internal override void OnLeave(IFsm<FsmTest> fsm)
{
Debug.Log("离开 WalkState");
}
protected internal override void OnUpdate(IFsm<FsmTest> fsm)
{
if (Input.GetKeyDown(KeyCode.B))
{
ChangeState<RunState>(fsm);
}
}
}
(三)RunState
csharp
public class RunState : FsmState<FsmTest>
{
protected internal override void OnDestroy(IFsm<FsmTest> fsm)
{
Debug.Log("销毁 RunState");
}
protected internal override void OnEnter(IFsm<FsmTest> fsm)
{
Debug.Log("进入 RunState");
}
protected internal override void OnInit(IFsm<FsmTest> fsm)
{
}
protected internal override void OnLeave(IFsm<FsmTest> fsm)
{
Debug.Log("离开 RunState");
}
protected internal override void OnUpdate(IFsm<FsmTest> fsm)
{
if (Input.GetKeyDown(KeyCode.C))
{
ChangeState<IdleState>(fsm);
}
}
}
mono测试
csharp
public class FsmTest : MonoBehaviour
{
private IFsm<FsmTest> m_TestFsm;
void Start()
{
SingletonSystem.Initialize();
AssemblyManager.Load(1, GetType().Assembly);
m_TestFsm = FsmManager.Instance.CreateFsm<FsmTest>("MyTestFsm",this, new IdleState(),new WalkState(),new RunState());
m_TestFsm.Start<IdleState>();
}
void Update()
{
SingletonSystem.Update();
if (Input.GetKeyDown(KeyCode.P))
{
FsmManager.Instance.DestroyFsm(m_TestFsm);
}
}
}