第一篇文章里说完了基础类和入口,现在从入口继续往下看。GameFramework简介里对流程是这么描述的:流程是贯穿游戏运行时整个生命周期的有限状态机。可以理解为游戏就是由一个个流程拼接起来的。所以接下来去看状态机和流程。
一、状态机
和框架的基础类类似。作者在定义状态机时也是分了两部分:状态机基类和状态机接口。
/// <summary>
/// 有限状态机基类。
/// </summary>
public abstract class FsmBase
{
private string m_Name;
/// <summary>
/// 初始化有限状态机基类的新实例。
/// </summary>
public FsmBase()
{
m_Name = string.Empty;
}
/// <summary>
/// 获取有限状态机名称。
/// </summary>
public string Name
{
get
{
return m_Name;
}
protected set
{
m_Name = value ?? string.Empty;
}
}
/// <summary>
/// 获取有限状态机完整名称。
/// </summary>
public string FullName
{
get
{
return new TypeNamePair(OwnerType, m_Name).ToString();
}
}
/// <summary>
/// 获取有限状态机持有者类型。
/// </summary>
public abstract Type OwnerType
{
get;
}
/// <summary>
/// 获取有限状态机中状态的数量。
/// </summary>
public abstract int FsmStateCount
{
get;
}
/// <summary>
/// 获取有限状态机是否正在运行。
/// </summary>
public abstract bool IsRunning
{
get;
}
/// <summary>
/// 获取有限状态机是否被销毁。
/// </summary>
public abstract bool IsDestroyed
{
get;
}
/// <summary>
/// 获取当前有限状态机状态名称。
/// </summary>
public abstract string CurrentStateName
{
get;
}
/// <summary>
/// 获取当前有限状态机状态持续时间。
/// </summary>
public abstract float CurrentStateTime
{
get;
}
/// <summary>
/// 有限状态机轮询。
/// </summary>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">当前已流逝时间,以秒为单位。</param>
internal abstract void Update(float elapseSeconds, float realElapseSeconds);
/// <summary>
/// 关闭并清理有限状态机。
/// </summary>
internal abstract void Shutdown();
}
基类里包含的方法还是那两个:Update() 和 ShutDown() ;属性的话有名字、持有者类型、当前状态名字、是否运行以及是否销毁,此外还有状态数量、当前状态运行时间。我在想是否有必要保存上个状态呢?
public interface IFsm<T> where T : class
{
/// <summary>
/// 获取有限状态机名称。
/// </summary>
string Name
{
get;
}
/// <summary>
/// 获取有限状态机完整名称。
/// </summary>
string FullName
{
get;
}
/// <summary>
/// 获取有限状态机持有者。
/// </summary>
T Owner
{
get;
}
/// <summary>
/// 获取有限状态机中状态的数量。
/// </summary>
int FsmStateCount
{
get;
}
/// <summary>
/// 获取有限状态机是否正在运行。
/// </summary>
bool IsRunning
{
get;
}
/// <summary>
/// 获取有限状态机是否被销毁。
/// </summary>
bool IsDestroyed
{
get;
}
/// <summary>
/// 获取当前有限状态机状态。
/// </summary>
FsmState<T> CurrentState
{
get;
}
/// <summary>
/// 获取当前有限状态机状态持续时间。
/// </summary>
float CurrentStateTime
{
get;
}
/// <summary>
/// 开始有限状态机。
/// </summary>
/// <typeparam name="TState">要开始的有限状态机状态类型。</typeparam>
void Start<TState>() where TState : FsmState<T>;
/// <summary>
/// 开始有限状态机。
/// </summary>
/// <param name="stateType">要开始的有限状态机状态类型。</param>
void Start(Type stateType);
/// <summary>
/// 是否存在有限状态机状态。
/// </summary>
/// <typeparam name="TState">要检查的有限状态机状态类型。</typeparam>
/// <returns>是否存在有限状态机状态。</returns>
bool HasState<TState>() where TState : FsmState<T>;
/// <summary>
/// 是否存在有限状态机状态。
/// </summary>
/// <param name="stateType">要检查的有限状态机状态类型。</param>
/// <returns>是否存在有限状态机状态。</returns>
bool HasState(Type stateType);
/// <summary>
/// 获取有限状态机状态。
/// </summary>
/// <typeparam name="TState">要获取的有限状态机状态类型。</typeparam>
/// <returns>要获取的有限状态机状态。</returns>
TState GetState<TState>() where TState : FsmState<T>;
/// <summary>
/// 获取有限状态机状态。
/// </summary>
/// <param name="stateType">要获取的有限状态机状态类型。</param>
/// <returns>要获取的有限状态机状态。</returns>
FsmState<T> GetState(Type stateType);
/// <summary>
/// 获取有限状态机的所有状态。
/// </summary>
/// <returns>有限状态机的所有状态。</returns>
FsmState<T>[] GetAllStates();
/// <summary>
/// 获取有限状态机的所有状态。
/// </summary>
/// <param name="results">有限状态机的所有状态。</param>
void GetAllStates(List<FsmState<T>> results);
/// <summary>
/// 是否存在有限状态机数据。
/// </summary>
/// <param name="name">有限状态机数据名称。</param>
/// <returns>有限状态机数据是否存在。</returns>
bool HasData(string name);
/// <summary>
/// 获取有限状态机数据。
/// </summary>
/// <typeparam name="TData">要获取的有限状态机数据的类型。</typeparam>
/// <param name="name">有限状态机数据名称。</param>
/// <returns>要获取的有限状态机数据。</returns>
TData GetData<TData>(string name) where TData : Variable;
/// <summary>
/// 获取有限状态机数据。
/// </summary>
/// <param name="name">有限状态机数据名称。</param>
/// <returns>要获取的有限状态机数据。</returns>
Variable GetData(string name);
/// <summary>
/// 设置有限状态机数据。
/// </summary>
/// <typeparam name="TData">要设置的有限状态机数据的类型。</typeparam>
/// <param name="name">有限状态机数据名称。</param>
/// <param name="data">要设置的有限状态机数据。</param>
void SetData<TData>(string name, TData data) where TData : Variable;
/// <summary>
/// 设置有限状态机数据。
/// </summary>
/// <param name="name">有限状态机数据名称。</param>
/// <param name="data">要设置的有限状态机数据。</param>
void SetData(string name, Variable data);
/// <summary>
/// 移除有限状态机数据。
/// </summary>
/// <param name="name">有限状态机数据名称。</param>
/// <returns>是否移除有限状态机数据成功。</returns>
bool RemoveData(string name);
}
状态机接口里的某些属性和基类里的是重复的:名字、状态数量、是否运行、是否销毁、当前状态运行时间;方法则有开始、判断状态存在、获取状态、移除状态、判断状态数据存在、获取状态数据、设置状态数据。看到这里有个问题为什么把IFsm和FsmBase分开写?想了想应该跟之前定义了GameFrameworkModule和对应Manager接口一样,为了方便扩展状态机。
接下来去定义状态的基类。
/// <summary>
/// 有限状态机状态基类。
/// </summary>
/// <typeparam name="T">有限状态机持有者类型。</typeparam>
public abstract class FsmState<T> where T : class
{
/// <summary>
/// 初始化有限状态机状态基类的新实例。
/// </summary>
public FsmState()
{
}
/// <summary>
/// 有限状态机状态初始化时调用。
/// </summary>
/// <param name="fsm">有限状态机引用。</param>
protected internal virtual void OnInit(IFsm<T> fsm)
{
}
/// <summary>
/// 有限状态机状态进入时调用。
/// </summary>
/// <param name="fsm">有限状态机引用。</param>
protected internal virtual void OnEnter(IFsm<T> fsm)
{
}
/// <summary>
/// 有限状态机状态轮询时调用。
/// </summary>
/// <param name="fsm">有限状态机引用。</param>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
protected internal virtual void OnUpdate(IFsm<T> fsm, float elapseSeconds, float realElapseSeconds)
{
}
/// <summary>
/// 有限状态机状态离开时调用。
/// </summary>
/// <param name="fsm">有限状态机引用。</param>
/// <param name="isShutdown">是否是关闭有限状态机时触发。</param>
protected internal virtual void OnLeave(IFsm<T> fsm, bool isShutdown)
{
}
/// <summary>
/// 有限状态机状态销毁时调用。
/// </summary>
/// <param name="fsm">有限状态机引用。</param>
protected internal virtual void OnDestroy(IFsm<T> fsm)
{
}
/// <summary>
/// 切换当前有限状态机状态。
/// </summary>
/// <typeparam name="TState">要切换到的有限状态机状态类型。</typeparam>
/// <param name="fsm">有限状态机引用。</param>
protected void ChangeState<TState>(IFsm<T> fsm) where TState : FsmState<T>
{
Fsm<T> fsmImplement = (Fsm<T>)fsm;
if (fsmImplement == null)
{
throw new GameFrameworkException("FSM is invalid.");
}
fsmImplement.ChangeState<TState>();
}
/// <summary>
/// 切换当前有限状态机状态。
/// </summary>
/// <param name="fsm">有限状态机引用。</param>
/// <param name="stateType">要切换到的有限状态机状态类型。</param>
protected void ChangeState(IFsm<T> fsm, Type stateType)
{
Fsm<T> fsmImplement = (Fsm<T>)fsm;
if (fsmImplement == null)
{
throw new GameFrameworkException("FSM is invalid.");
}
if (stateType == null)
{
throw new GameFrameworkException("State type is invalid.");
}
if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
{
throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName));
}
fsmImplement.ChangeState(stateType);
}
}
状态里除了状态的生命周期以外,还有修改状态机状态的方法。这里不太常见的是方法的参数类型是个泛型接口:IFsm<T>。通常参数要么是个接口,要么是个泛型,这次遇到个泛型接口。但本质上还是个接口,所以状态对象还是以状态机对象作为参数来执行各种操作。修改状态的方法里调用了type.IsAssignableFrom(Type t):如果t是type或者继承了type则返回true
有了这些就可以构造出一个状态机。
internal sealed class Fsm<T> : FsmBase, IReference, IFsm<T> where T : class
{
private T m_Owner;
private readonly Dictionary<Type, FsmState<T>> m_States;
private Dictionary<string, Variable> m_Datas;
private FsmState<T> m_CurrentState;
private float m_CurrentStateTime;
private bool m_IsDestroyed;
/// <summary>
/// 初始化有限状态机的新实例。
/// </summary>
public Fsm()
{
m_Owner = null;
m_States = new Dictionary<Type, FsmState<T>>();
m_Datas = null;
m_CurrentState = null;
m_CurrentStateTime = 0f;
m_IsDestroyed = true;
}
/// <summary>
/// 获取有限状态机持有者。
/// </summary>
public T Owner
{
get
{
return m_Owner;
}
}
/// <summary>
/// 获取有限状态机持有者类型。
/// </summary>
public override Type OwnerType
{
get
{
return typeof(T);
}
}
/// <summary>
/// 获取有限状态机中状态的数量。
/// </summary>
public override int FsmStateCount
{
get
{
return m_States.Count;
}
}
/// <summary>
/// 获取有限状态机是否正在运行。
/// </summary>
public override bool IsRunning
{
get
{
return m_CurrentState != null;
}
}
/// <summary>
/// 获取有限状态机是否被销毁。
/// </summary>
public override bool IsDestroyed
{
get
{
return m_IsDestroyed;
}
}
/// <summary>
/// 获取当前有限状态机状态。
/// </summary>
public FsmState<T> CurrentState
{
get
{
return m_CurrentState;
}
}
/// <summary>
/// 获取当前有限状态机状态名称。
/// </summary>
public override string CurrentStateName
{
get
{
return m_CurrentState != null ? m_CurrentState.GetType().FullName : null;
}
}
/// <summary>
/// 获取当前有限状态机状态持续时间。
/// </summary>
public override float CurrentStateTime
{
get
{
return m_CurrentStateTime;
}
}
/// <summary>
/// 创建有限状态机。
/// </summary>
/// <param name="name">有限状态机名称。</param>
/// <param name="owner">有限状态机持有者。</param>
/// <param name="states">有限状态机状态集合。</param>
/// <returns>创建的有限状态机。</returns>
public static Fsm<T> Create(string name, T owner, params FsmState<T>[] states)
{
if (owner == null)
{
throw new GameFrameworkException("FSM owner is invalid.");
}
if (states == null || states.Length < 1)
{
throw new GameFrameworkException("FSM states is invalid.");
}
Fsm<T> fsm = ReferencePool.Acquire<Fsm<T>>();
fsm.Name = name;
fsm.m_Owner = owner;
fsm.m_IsDestroyed = false;
foreach (FsmState<T> state in states)
{
if (state == null)
{
throw new GameFrameworkException("FSM states is invalid.");
}
Type stateType = state.GetType();
if (fsm.m_States.ContainsKey(stateType))
{
throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' state '{1}' is already exist.", new TypeNamePair(typeof(T), name).ToString(), stateType));
}
fsm.m_States.Add(stateType, state);
state.OnInit(fsm);
}
return fsm;
}
/// <summary>
/// 创建有限状态机。
/// </summary>
/// <param name="name">有限状态机名称。</param>
/// <param name="owner">有限状态机持有者。</param>
/// <param name="states">有限状态机状态集合。</param>
/// <returns>创建的有限状态机。</returns>
public static Fsm<T> Create(string name, T owner, List<FsmState<T>> states)
{
if (owner == null)
{
throw new GameFrameworkException("FSM owner is invalid.");
}
if (states == null || states.Count < 1)
{
throw new GameFrameworkException("FSM states is invalid.");
}
Fsm<T> fsm = ReferencePool.Acquire<Fsm<T>>();
fsm.Name = name;
fsm.m_Owner = owner;
fsm.m_IsDestroyed = false;
foreach (FsmState<T> state in states)
{
if (state == null)
{
throw new GameFrameworkException("FSM states is invalid.");
}
Type stateType = state.GetType();
if (fsm.m_States.ContainsKey(stateType))
{
throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' state '{1}' is already exist.", new TypeNamePair(typeof(T), name).ToString(), stateType));
}
fsm.m_States.Add(stateType, state);
state.OnInit(fsm);
}
return fsm;
}
/// <summary>
/// 清理有限状态机。
/// </summary>
public void Clear()
{
if (m_CurrentState != null)
{
m_CurrentState.OnLeave(this, true);
}
foreach (KeyValuePair<Type, FsmState<T>> state in m_States)
{
state.Value.OnDestroy(this);
}
Name = null;
m_Owner = null;
m_States.Clear();
if (m_Datas != null)
{
foreach (KeyValuePair<string, Variable> data in m_Datas)
{
if (data.Value == null)
{
continue;
}
ReferencePool.Release(data.Value);
}
m_Datas.Clear();
}
m_CurrentState = null;
m_CurrentStateTime = 0f;
m_IsDestroyed = true;
}
/// <summary>
/// 开始有限状态机。
/// </summary>
/// <typeparam name="TState">要开始的有限状态机状态类型。</typeparam>
public void Start<TState>() where TState : FsmState<T>
{
if (IsRunning)
{
throw new GameFrameworkException("FSM is running, can not start again.");
}
FsmState<T> state = GetState<TState>();
if (state == null)
{
throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not start state '{1}' which is not exist.", new TypeNamePair(typeof(T), Name).ToString(), typeof(TState).FullName));
}
m_CurrentStateTime = 0f;
m_CurrentState = state;
m_CurrentState.OnEnter(this);
}
/// <summary>
/// 开始有限状态机。
/// </summary>
/// <param name="stateType">要开始的有限状态机状态类型。</param>
public void Start(Type stateType)
{
if (IsRunning)
{
throw new GameFrameworkException("FSM is running, can not start again.");
}
if (stateType == null)
{
throw new GameFrameworkException("State type is invalid.");
}
if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
{
throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName));
}
FsmState<T> state = GetState(stateType);
if (state == null)
{
throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not start state '{1}' which is not exist.", new TypeNamePair(typeof(T), Name).ToString(), stateType.FullName));
}
m_CurrentStateTime = 0f;
m_CurrentState = state;
m_CurrentState.OnEnter(this);
}
/// <summary>
/// 是否存在有限状态机状态。
/// </summary>
/// <typeparam name="TState">要检查的有限状态机状态类型。</typeparam>
/// <returns>是否存在有限状态机状态。</returns>
public bool HasState<TState>() where TState : FsmState<T>
{
return m_States.ContainsKey(typeof(TState));
}
/// <summary>
/// 是否存在有限状态机状态。
/// </summary>
/// <param name="stateType">要检查的有限状态机状态类型。</param>
/// <returns>是否存在有限状态机状态。</returns>
public bool HasState(Type stateType)
{
if (stateType == null)
{
throw new GameFrameworkException("State type is invalid.");
}
if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
{
throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName));
}
return m_States.ContainsKey(stateType);
}
/// <summary>
/// 获取有限状态机状态。
/// </summary>
/// <typeparam name="TState">要获取的有限状态机状态类型。</typeparam>
/// <returns>要获取的有限状态机状态。</returns>
public TState GetState<TState>() where TState : FsmState<T>
{
FsmState<T> state = null;
if (m_States.TryGetValue(typeof(TState), out state))
{
return (TState)state;
}
return null;
}
/// <summary>
/// 获取有限状态机状态。
/// </summary>
/// <param name="stateType">要获取的有限状态机状态类型。</param>
/// <returns>要获取的有限状态机状态。</returns>
public FsmState<T> GetState(Type stateType)
{
if (stateType == null)
{
throw new GameFrameworkException("State type is invalid.");
}
if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
{
throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName));
}
FsmState<T> state = null;
if (m_States.TryGetValue(stateType, out state))
{
return state;
}
return null;
}
/// <summary>
/// 获取有限状态机的所有状态。
/// </summary>
/// <returns>有限状态机的所有状态。</returns>
public FsmState<T>[] GetAllStates()
{
int index = 0;
FsmState<T>[] results = new FsmState<T>[m_States.Count];
foreach (KeyValuePair<Type, FsmState<T>> state in m_States)
{
results[index++] = state.Value;
}
return results;
}
/// <summary>
/// 获取有限状态机的所有状态。
/// </summary>
/// <param name="results">有限状态机的所有状态。</param>
public void GetAllStates(List<FsmState<T>> results)
{
if (results == null)
{
throw new GameFrameworkException("Results is invalid.");
}
results.Clear();
foreach (KeyValuePair<Type, FsmState<T>> state in m_States)
{
results.Add(state.Value);
}
}
/// <summary>
/// 是否存在有限状态机数据。
/// </summary>
/// <param name="name">有限状态机数据名称。</param>
/// <returns>有限状态机数据是否存在。</returns>
public bool HasData(string name)
{
if (string.IsNullOrEmpty(name))
{
throw new GameFrameworkException("Data name is invalid.");
}
if (m_Datas == null)
{
return false;
}
return m_Datas.ContainsKey(name);
}
/// <summary>
/// 获取有限状态机数据。
/// </summary>
/// <typeparam name="TData">要获取的有限状态机数据的类型。</typeparam>
/// <param name="name">有限状态机数据名称。</param>
/// <returns>要获取的有限状态机数据。</returns>
public TData GetData<TData>(string name) where TData : Variable
{
return (TData)GetData(name);
}
/// <summary>
/// 获取有限状态机数据。
/// </summary>
/// <param name="name">有限状态机数据名称。</param>
/// <returns>要获取的有限状态机数据。</returns>
public Variable GetData(string name)
{
if (string.IsNullOrEmpty(name))
{
throw new GameFrameworkException("Data name is invalid.");
}
if (m_Datas == null)
{
return null;
}
Variable data = null;
if (m_Datas.TryGetValue(name, out data))
{
return data;
}
return null;
}
/// <summary>
/// 设置有限状态机数据。
/// </summary>
/// <typeparam name="TData">要设置的有限状态机数据的类型。</typeparam>
/// <param name="name">有限状态机数据名称。</param>
/// <param name="data">要设置的有限状态机数据。</param>
public void SetData<TData>(string name, TData data) where TData : Variable
{
SetData(name, (Variable)data);
}
/// <summary>
/// 设置有限状态机数据。
/// </summary>
/// <param name="name">有限状态机数据名称。</param>
/// <param name="data">要设置的有限状态机数据。</param>
public void SetData(string name, Variable data)
{
if (string.IsNullOrEmpty(name))
{
throw new GameFrameworkException("Data name is invalid.");
}
if (m_Datas == null)
{
m_Datas = new Dictionary<string, Variable>(StringComparer.Ordinal);
}
Variable oldData = GetData(name);
if (oldData != null)
{
ReferencePool.Release(oldData);
}
m_Datas[name] = data;
}
/// <summary>
/// 移除有限状态机数据。
/// </summary>
/// <param name="name">有限状态机数据名称。</param>
/// <returns>是否移除有限状态机数据成功。</returns>
public bool RemoveData(string name)
{
if (string.IsNullOrEmpty(name))
{
throw new GameFrameworkException("Data name is invalid.");
}
if (m_Datas == null)
{
return false;
}
Variable oldData = GetData(name);
if (oldData != null)
{
ReferencePool.Release(oldData);
}
return m_Datas.Remove(name);
}
/// <summary>
/// 有限状态机轮询。
/// </summary>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
internal override void Update(float elapseSeconds, float realElapseSeconds)
{
if (m_CurrentState == null)
{
return;
}
m_CurrentStateTime += elapseSeconds;
m_CurrentState.OnUpdate(this, elapseSeconds, realElapseSeconds);
}
/// <summary>
/// 关闭并清理有限状态机。
/// </summary>
internal override void Shutdown()
{
ReferencePool.Release(this);
}
/// <summary>
/// 切换当前有限状态机状态。
/// </summary>
/// <typeparam name="TState">要切换到的有限状态机状态类型。</typeparam>
internal void ChangeState<TState>() where TState : FsmState<T>
{
ChangeState(typeof(TState));
}
/// <summary>
/// 切换当前有限状态机状态。
/// </summary>
/// <param name="stateType">要切换到的有限状态机状态类型。</param>
internal void ChangeState(Type stateType)
{
if (m_CurrentState == null)
{
throw new GameFrameworkException("Current state is invalid.");
}
FsmState<T> state = GetState(stateType);
if (state == null)
{
throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not change state to '{1}' which is not exist.", new TypeNamePair(typeof(T), Name).ToString(), stateType.FullName));
}
m_CurrentState.OnLeave(this, false);
m_CurrentStateTime = 0f;
m_CurrentState = state;
m_CurrentState.OnEnter(this);
}
}
状态机类继承了FsmBase和接口IFsm。里面跟我想的不一样的就是那个存储了字符串和变量的字典Dictionary<string, Variable> m_Datas(Variable是自定义的一个类,这个类包含两个属性:类型Type和值Value)。 好吧,其实看了接口里声明的方法,就应该想到有这个结构的,但是目前还没想到这个东西要怎么用。还有就是Create的两个重载。除了参数里状态集合类型不同(一个是数组,一个是list)以外代码一模一样。如果是我写的话很大概率会把数组转成list然后再调用另一个重载。作者这个写法不用说肯定是基于性能考量。
接下来需要写状态机的管理类。
internal sealed class FsmManager : GameFrameworkModule, IFsmManager
{
private readonly Dictionary<TypeNamePair, FsmBase> m_Fsms;
private readonly List<FsmBase> m_TempFsms;
/// <summary>
/// 初始化有限状态机管理器的新实例。
/// </summary>
public FsmManager()
{
m_Fsms = new Dictionary<TypeNamePair, FsmBase>();
m_TempFsms = new List<FsmBase>();
}
/// <summary>
/// 获取游戏框架模块优先级。
/// </summary>
/// <remarks>优先级较高的模块会优先轮询,并且关闭操作会后进行。</remarks>
internal override int Priority
{
get
{
return 60;
}
}
/// <summary>
/// 获取有限状态机数量。
/// </summary>
public int Count
{
get
{
return m_Fsms.Count;
}
}
/// <summary>
/// 有限状态机管理器轮询。
/// </summary>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
internal override void Update(float elapseSeconds, float realElapseSeconds)
{
m_TempFsms.Clear();
if (m_Fsms.Count <= 0)
{
return;
}
foreach (KeyValuePair<TypeNamePair, FsmBase> fsm in m_Fsms)
{
m_TempFsms.Add(fsm.Value);
}
foreach (FsmBase fsm in m_TempFsms)
{
if (fsm.IsDestroyed)
{
continue;
}
fsm.Update(elapseSeconds, realElapseSeconds);
}
}
/// <summary>
/// 关闭并清理有限状态机管理器。
/// </summary>
internal override void Shutdown()
{
foreach (KeyValuePair<TypeNamePair, FsmBase> fsm in m_Fsms)
{
fsm.Value.Shutdown();
}
m_Fsms.Clear();
m_TempFsms.Clear();
}
/// <summary>
/// 检查是否存在有限状态机。
/// </summary>
/// <typeparam name="T">有限状态机持有者类型。</typeparam>
/// <returns>是否存在有限状态机。</returns>
public bool HasFsm<T>() where T : class
{
return InternalHasFsm(new TypeNamePair(typeof(T)));
}
/// <summary>
/// 检查是否存在有限状态机。
/// </summary>
/// <param name="ownerType">有限状态机持有者类型。</param>
/// <returns>是否存在有限状态机。</returns>
public bool HasFsm(Type ownerType)
{
if (ownerType == null)
{
throw new GameFrameworkException("Owner type is invalid.");
}
return InternalHasFsm(new TypeNamePair(ownerType));
}
/// <summary>
/// 检查是否存在有限状态机。
/// </summary>
/// <typeparam name="T">有限状态机持有者类型。</typeparam>
/// <param name="name">有限状态机名称。</param>
/// <returns>是否存在有限状态机。</returns>
public bool HasFsm<T>(string name) where T : class
{
return InternalHasFsm(new TypeNamePair(typeof(T), name));
}
/// <summary>
/// 检查是否存在有限状态机。
/// </summary>
/// <param name="ownerType">有限状态机持有者类型。</param>
/// <param name="name">有限状态机名称。</param>
/// <returns>是否存在有限状态机。</returns>
public bool HasFsm(Type ownerType, string name)
{
if (ownerType == null)
{
throw new GameFrameworkException("Owner type is invalid.");
}
return InternalHasFsm(new TypeNamePair(ownerType, name));
}
/// <summary>
/// 获取有限状态机。
/// </summary>
/// <typeparam name="T">有限状态机持有者类型。</typeparam>
/// <returns>要获取的有限状态机。</returns>
public IFsm<T> GetFsm<T>() where T : class
{
return (IFsm<T>)InternalGetFsm(new TypeNamePair(typeof(T)));
}
/// <summary>
/// 获取有限状态机。
/// </summary>
/// <param name="ownerType">有限状态机持有者类型。</param>
/// <returns>要获取的有限状态机。</returns>
public FsmBase GetFsm(Type ownerType)
{
if (ownerType == null)
{
throw new GameFrameworkException("Owner type is invalid.");
}
return InternalGetFsm(new TypeNamePair(ownerType));
}
/// <summary>
/// 获取有限状态机。
/// </summary>
/// <typeparam name="T">有限状态机持有者类型。</typeparam>
/// <param name="name">有限状态机名称。</param>
/// <returns>要获取的有限状态机。</returns>
public IFsm<T> GetFsm<T>(string name) where T : class
{
return (IFsm<T>)InternalGetFsm(new TypeNamePair(typeof(T), name));
}
/// <summary>
/// 获取有限状态机。
/// </summary>
/// <param name="ownerType">有限状态机持有者类型。</param>
/// <param name="name">有限状态机名称。</param>
/// <returns>要获取的有限状态机。</returns>
public FsmBase GetFsm(Type ownerType, string name)
{
if (ownerType == null)
{
throw new GameFrameworkException("Owner type is invalid.");
}
return InternalGetFsm(new TypeNamePair(ownerType, name));
}
/// <summary>
/// 获取所有有限状态机。
/// </summary>
/// <returns>所有有限状态机。</returns>
public FsmBase[] GetAllFsms()
{
int index = 0;
FsmBase[] results = new FsmBase[m_Fsms.Count];
foreach (KeyValuePair<TypeNamePair, FsmBase> fsm in m_Fsms)
{
results[index++] = fsm.Value;
}
return results;
}
/// <summary>
/// 获取所有有限状态机。
/// </summary>
/// <param name="results">所有有限状态机。</param>
public void GetAllFsms(List<FsmBase> results)
{
if (results == null)
{
throw new GameFrameworkException("Results is invalid.");
}
results.Clear();
foreach (KeyValuePair<TypeNamePair, FsmBase> fsm in m_Fsms)
{
results.Add(fsm.Value);
}
}
/// <summary>
/// 创建有限状态机。
/// </summary>
/// <typeparam name="T">有限状态机持有者类型。</typeparam>
/// <param name="owner">有限状态机持有者。</param>
/// <param name="states">有限状态机状态集合。</param>
/// <returns>要创建的有限状态机。</returns>
public IFsm<T> CreateFsm<T>(T owner, params FsmState<T>[] states) where T : class
{
return CreateFsm(string.Empty, owner, states);
}
/// <summary>
/// 创建有限状态机。
/// </summary>
/// <typeparam name="T">有限状态机持有者类型。</typeparam>
/// <param name="name">有限状态机名称。</param>
/// <param name="owner">有限状态机持有者。</param>
/// <param name="states">有限状态机状态集合。</param>
/// <returns>要创建的有限状态机。</returns>
public IFsm<T> CreateFsm<T>(string name, T owner, params FsmState<T>[] states) where T : class
{
TypeNamePair typeNamePair = new TypeNamePair(typeof(T), name);
if (HasFsm<T>(name))
{
throw new GameFrameworkException(Utility.Text.Format("Already exist FSM '{0}'.", typeNamePair.ToString()));
}
Fsm<T> fsm = Fsm<T>.Create(name, owner, states);
m_Fsms.Add(typeNamePair, fsm);
return fsm;
}
/// <summary>
/// 创建有限状态机。
/// </summary>
/// <typeparam name="T">有限状态机持有者类型。</typeparam>
/// <param name="owner">有限状态机持有者。</param>
/// <param name="states">有限状态机状态集合。</param>
/// <returns>要创建的有限状态机。</returns>
public IFsm<T> CreateFsm<T>(T owner, List<FsmState<T>> states) where T : class
{
return CreateFsm(string.Empty, owner, states);
}
/// <summary>
/// 创建有限状态机。
/// </summary>
/// <typeparam name="T">有限状态机持有者类型。</typeparam>
/// <param name="name">有限状态机名称。</param>
/// <param name="owner">有限状态机持有者。</param>
/// <param name="states">有限状态机状态集合。</param>
/// <returns>要创建的有限状态机。</returns>
public IFsm<T> CreateFsm<T>(string name, T owner, List<FsmState<T>> states) where T : class
{
TypeNamePair typeNamePair = new TypeNamePair(typeof(T), name);
if (HasFsm<T>(name))
{
throw new GameFrameworkException(Utility.Text.Format("Already exist FSM '{0}'.", typeNamePair));
}
Fsm<T> fsm = Fsm<T>.Create(name, owner, states);
m_Fsms.Add(typeNamePair, fsm);
return fsm;
}
/// <summary>
/// 销毁有限状态机。
/// </summary>
/// <typeparam name="T">有限状态机持有者类型。</typeparam>
/// <returns>是否销毁有限状态机成功。</returns>
public bool DestroyFsm<T>() where T : class
{
return InternalDestroyFsm(new TypeNamePair(typeof(T)));
}
/// <summary>
/// 销毁有限状态机。
/// </summary>
/// <param name="ownerType">有限状态机持有者类型。</param>
/// <returns>是否销毁有限状态机成功。</returns>
public bool DestroyFsm(Type ownerType)
{
if (ownerType == null)
{
throw new GameFrameworkException("Owner type is invalid.");
}
return InternalDestroyFsm(new TypeNamePair(ownerType));
}
/// <summary>
/// 销毁有限状态机。
/// </summary>
/// <typeparam name="T">有限状态机持有者类型。</typeparam>
/// <param name="name">要销毁的有限状态机名称。</param>
/// <returns>是否销毁有限状态机成功。</returns>
public bool DestroyFsm<T>(string name) where T : class
{
return InternalDestroyFsm(new TypeNamePair(typeof(T), name));
}
/// <summary>
/// 销毁有限状态机。
/// </summary>
/// <param name="ownerType">有限状态机持有者类型。</param>
/// <param name="name">要销毁的有限状态机名称。</param>
/// <returns>是否销毁有限状态机成功。</returns>
public bool DestroyFsm(Type ownerType, string name)
{
if (ownerType == null)
{
throw new GameFrameworkException("Owner type is invalid.");
}
return InternalDestroyFsm(new TypeNamePair(ownerType, name));
}
/// <summary>
/// 销毁有限状态机。
/// </summary>
/// <typeparam name="T">有限状态机持有者类型。</typeparam>
/// <param name="fsm">要销毁的有限状态机。</param>
/// <returns>是否销毁有限状态机成功。</returns>
public bool DestroyFsm<T>(IFsm<T> fsm) where T : class
{
if (fsm == null)
{
throw new GameFrameworkException("FSM is invalid.");
}
return InternalDestroyFsm(new TypeNamePair(typeof(T), fsm.Name));
}
/// <summary>
/// 销毁有限状态机。
/// </summary>
/// <param name="fsm">要销毁的有限状态机。</param>
/// <returns>是否销毁有限状态机成功。</returns>
public bool DestroyFsm(FsmBase fsm)
{
if (fsm == null)
{
throw new GameFrameworkException("FSM is invalid.");
}
return InternalDestroyFsm(new TypeNamePair(fsm.OwnerType, fsm.Name));
}
private bool InternalHasFsm(TypeNamePair typeNamePair)
{
return m_Fsms.ContainsKey(typeNamePair);
}
private FsmBase InternalGetFsm(TypeNamePair typeNamePair)
{
FsmBase fsm = null;
if (m_Fsms.TryGetValue(typeNamePair, out fsm))
{
return fsm;
}
return null;
}
private bool InternalDestroyFsm(TypeNamePair typeNamePair)
{
FsmBase fsm = null;
if (m_Fsms.TryGetValue(typeNamePair, out fsm))
{
fsm.Shutdown();
return m_Fsms.Remove(typeNamePair);
}
return false;
}
}
就像一开始说的那样,每个manager除了继承GameFrameworkModule以外还实现了IFsmManager。注意到这里的字典和list使用的都是FsmBase而不是IFsmManager,此外还定义了TypeNamePair。这个类的存在是为了方便做Type到string的映射,没啥好讲的。但是在TypeNamePair里遇见了一个没见过的特性:StructLayout。这个特性的作用是允许控制内存中类或结构的数据字段的物理布局。平常在C#代码中使用类或者结构体时,不需要使用此特性。但在与非托管代码时交互,需要使用StructLayoutAttribute特性来控制类型的非托管布局。StructLayoutAttribute常用构造函数是:
StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind),其中System.Runtime.InteropServices.LayoutKind是一个枚举类型,有三个取值。
- LayoutKind.Sequential 强制按成员的显示顺序对其进行排列。对于blittable类型,在托管和非托管内存中控制布局。对于non-blittable类型,它会在将类或者结构体封送到非托管代码时控制布局(换言之,如果仅在C#中进行调用,不会做任何操作,在与非托管代码交互时,仅控制送入非托管代码的布局)
- LayoutKind.Explicit 控制每个数据成员的精确位置,这会影响托管和非托管代码中的布局,不管是blittable类型还是non-blittable类型。使用LayoutKind.Explicit时,需要使用FieldOffsetAttribute特性指示类型中每个字段的位置。
- 默认情况下,编译器会将LayoutKind.Sequential应用到结构体,对于类,则需要显式应用LayoutKind.Sequential值。1
那么到这里就创建了一个状态机,接下来就要填充状态(也就是流程)了。
二、流程
首先给流程定义一个基类,以方便扩展。
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;
public abstract class ProcedureBase : FsmState<IProcedureManager>
{
/// <summary>
/// 状态初始化时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
protected internal override void OnInit(ProcedureOwner procedureOwner)
{
base.OnInit(procedureOwner);
}
/// <summary>
/// 进入状态时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
protected internal override void OnEnter(ProcedureOwner procedureOwner)
{
base.OnEnter(procedureOwner);
}
/// <summary>
/// 状态轮询时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
protected internal override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
}
/// <summary>
/// 离开状态时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
/// <param name="isShutdown">是否是关闭状态机时触发。</param>
protected internal override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
{
base.OnLeave(procedureOwner, isShutdown);
}
/// <summary>
/// 状态销毁时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
protected internal override void OnDestroy(ProcedureOwner procedureOwner)
{
base.OnDestroy(procedureOwner);
}
}
这个基类功能比较简单,就是继承了FsmState<IProcedureManager>,只包含了一个状态基本的生命周期。那去看一下IProcedureManager这个接口。
/// <summary>
/// 流程管理器接口。
/// </summary>
public interface IProcedureManager
{
/// <summary>
/// 获取当前流程。
/// </summary>
ProcedureBase CurrentProcedure
{
get;
}
/// <summary>
/// 获取当前流程持续时间。
/// </summary>
float CurrentProcedureTime
{
get;
}
/// <summary>
/// 初始化流程管理器。
/// </summary>
/// <param name="fsmManager">有限状态机管理器。</param>
/// <param name="procedures">流程管理器包含的流程。</param>
void Initialize(IFsmManager fsmManager, params ProcedureBase[] procedures);
/// <summary>
/// 开始流程。
/// </summary>
/// <typeparam name="T">要开始的流程类型。</typeparam>
void StartProcedure<T>() where T : ProcedureBase;
/// <summary>
/// 开始流程。
/// </summary>
/// <param name="procedureType">要开始的流程类型。</param>
void StartProcedure(Type procedureType);
/// <summary>
/// 是否存在流程。
/// </summary>
/// <typeparam name="T">要检查的流程类型。</typeparam>
/// <returns>是否存在流程。</returns>
bool HasProcedure<T>() where T : ProcedureBase;
/// <summary>
/// 是否存在流程。
/// </summary>
/// <param name="procedureType">要检查的流程类型。</param>
/// <returns>是否存在流程。</returns>
bool HasProcedure(Type procedureType);
/// <summary>
/// 获取流程。
/// </summary>
/// <typeparam name="T">要获取的流程类型。</typeparam>
/// <returns>要获取的流程。</returns>
ProcedureBase GetProcedure<T>() where T : ProcedureBase;
/// <summary>
/// 获取流程。
/// </summary>
/// <param name="procedureType">要获取的流程类型。</param>
/// <returns>要获取的流程。</returns>
ProcedureBase GetProcedure(Type procedureType);
}
这个接口除了判断和获取流程以外就只有初始化流程和开始流程两个方法,为什么没有更新流程和销毁流程呢?因为ProcedureManager在实现IProcedureManager的同时也继承了GameFrameworkModule,更新和销毁在GameFrameworkModule里面
/// <summary>
/// 流程管理器。
/// </summary>
internal sealed class ProcedureManager : GameFrameworkModule, IProcedureManager
{
private IFsmManager m_FsmManager;
private IFsm<IProcedureManager> m_ProcedureFsm;
/// <summary>
/// 初始化流程管理器的新实例。
/// </summary>
public ProcedureManager()
{
m_FsmManager = null;
m_ProcedureFsm = null;
}
/// <summary>
/// 获取游戏框架模块优先级。
/// </summary>
/// <remarks>优先级较高的模块会优先轮询,并且关闭操作会后进行。</remarks>
internal override int Priority
{
get
{
return -10;
}
}
/// <summary>
/// 获取当前流程。
/// </summary>
public ProcedureBase CurrentProcedure
{
get
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
return (ProcedureBase)m_ProcedureFsm.CurrentState;
}
}
/// <summary>
/// 获取当前流程持续时间。
/// </summary>
public float CurrentProcedureTime
{
get
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
return m_ProcedureFsm.CurrentStateTime;
}
}
/// <summary>
/// 流程管理器轮询。
/// </summary>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
internal override void Update(float elapseSeconds, float realElapseSeconds)
{
}
/// <summary>
/// 关闭并清理流程管理器。
/// </summary>
internal override void Shutdown()
{
if (m_FsmManager != null)
{
if (m_ProcedureFsm != null)
{
m_FsmManager.DestroyFsm(m_ProcedureFsm);
m_ProcedureFsm = null;
}
m_FsmManager = null;
}
}
/// <summary>
/// 初始化流程管理器。
/// </summary>
/// <param name="fsmManager">有限状态机管理器。</param>
/// <param name="procedures">流程管理器包含的流程。</param>
public void Initialize(IFsmManager fsmManager, params ProcedureBase[] procedures)
{
if (fsmManager == null)
{
throw new GameFrameworkException("FSM manager is invalid.");
}
m_FsmManager = fsmManager;
m_ProcedureFsm = m_FsmManager.CreateFsm(this, procedures);
}
/// <summary>
/// 开始流程。
/// </summary>
/// <typeparam name="T">要开始的流程类型。</typeparam>
public void StartProcedure<T>() where T : ProcedureBase
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
m_ProcedureFsm.Start<T>();
}
/// <summary>
/// 开始流程。
/// </summary>
/// <param name="procedureType">要开始的流程类型。</param>
public void StartProcedure(Type procedureType)
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
m_ProcedureFsm.Start(procedureType);
}
/// <summary>
/// 是否存在流程。
/// </summary>
/// <typeparam name="T">要检查的流程类型。</typeparam>
/// <returns>是否存在流程。</returns>
public bool HasProcedure<T>() where T : ProcedureBase
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
return m_ProcedureFsm.HasState<T>();
}
/// <summary>
/// 是否存在流程。
/// </summary>
/// <param name="procedureType">要检查的流程类型。</param>
/// <returns>是否存在流程。</returns>
public bool HasProcedure(Type procedureType)
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
return m_ProcedureFsm.HasState(procedureType);
}
/// <summary>
/// 获取流程。
/// </summary>
/// <typeparam name="T">要获取的流程类型。</typeparam>
/// <returns>要获取的流程。</returns>
public ProcedureBase GetProcedure<T>() where T : ProcedureBase
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
return m_ProcedureFsm.GetState<T>();
}
/// <summary>
/// 获取流程。
/// </summary>
/// <param name="procedureType">要获取的流程类型。</param>
/// <returns>要获取的流程。</returns>
public ProcedureBase GetProcedure(Type procedureType)
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
return (ProcedureBase)m_ProcedureFsm.GetState(procedureType);
}
}
画成类图大概是这样的: