提供创建、使用和销毁有限状态机的功能,一些适用于有限状态机机制的游戏逻辑,使用此模块将是一个不错的选择。
常规用法
获取有限状态机组件
1 |
FsmComponent fsmComponent = GameEntry.GetComponent<FsmComponent>(); |
定义状态
有限状态机的状态均派生自 FsmState<T>,T 为有限状态机的持有者类型。
例如:为 Actor 类定义站立(IdleState)和移动(MoveState)两个状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/// <summary> /// 定义站立状态。 /// </summary> public class IdleState : FsmState<Actor> { protected override void OnInit(IFsm<Actor> fsm) { // 创建有限状态机时调用 base.OnInit(fsm); Log.Info("创建站立状态。"); } protected override void OnDestroy(IFsm<Actor> fsm) { // 销毁有限状态机时调用 base.OnDestroy(fsm); Log.Info("销毁站立状态。"); } protected override void OnEnter(IFsm<Actor> fsm) { // 进入本状态时调用 base.OnEnter(fsm); Log.Info("进入站立状态。"); } protected override void OnLeave(IFsm<Actor> fsm, bool isShutdown) { // 离开本状态时调用 base.OnLeave(fsm, isShutdown); Log.Info("离开站立状态。"); } protected override void OnUpdate(IFsm<Actor> fsm, float elapseSeconds, float realElapseSeconds) { // 本状态被轮询时调用 base.OnUpdate(fsm, elapseSeconds, realElapseSeconds); Log.Info("轮询站立状态。"); } } |
1 2 3 4 5 6 |
/// <summary> /// 定义移动状态。 /// </summary> public class MoveState : FsmState<Actor> { } |
检查是否存在有限状态机
1 2 3 4 5 6 7 8 9 10 11 |
// 检查是否存在有限状态机,持有者类型为 Actor,有限状态机名称为空 bool hasFsm1 = fsmComponent.HasFsm<Actor>(); // 检查是否存在有限状态机,持有者类型为 Actor,有限状态机名称为空 bool hasFsm2 = fsmComponent.HasFsm(typeof(Actor)); // 检查是否存在有限状态机,持有者类型为 Actor,有限状态机名称为 FsmName bool hasFsm3 = fsmComponent.HasFsm<Actor>("FsmName"); // 检查是否存在有限状态机,持有者类型为 Actor,有限状态机名称为 FsmName bool hasFsm4 = fsmComponent.HasFsm(typeof(Actor), "FsmName"); |
获取有限状态机
1 2 3 4 5 6 7 8 9 10 11 |
// 获取有限状态机,持有者类型为 Actor,有限状态机名称为空 IFsm<Actor> fsm1 = fsmComponent.GetFsm<Actor>(); // 获取有限状态机,持有者类型为 Actor,有限状态机名称为空 IFsm<Actor> fsm2 = (IFsm<Actor>)fsmComponent.GetFsm(typeof(Actor)); // 获取有限状态机,持有者类型为 Actor,有限状态机名称为 FsmName IFsm<Actor> fsm3 = fsmComponent.GetFsm<Actor>("FsmName"); // 获取有限状态机,持有者类型为 Actor,有限状态机名称为 FsmName IFsm<Actor> fsm4 = (IFsm<Actor>)fsmComponent.GetFsm(typeof(Actor), "FsmName"); |
创建有限状态机
如果某个持有者类型只会拥有一个有限状态机,一般不需要带有状态机名称参数。但如果同一持有者类型下会有多个有限状态机,则需要带有状态机名称参数,比如有很多持有者实例,每个实例各使用一个同类型状态机的情况。
1 2 3 4 5 |
// 创建有限状态机,持有者为 owner,其类型为 Actor,有限状态机名称为空,加入 IdleState 和 MoveState 两个状态 IFsm<Actor> fsm1 = fsmComponent.CreateFsm<Actor>(owner, new IdleState(), new MoveState()); // 创建有限状态机,持有者为 owner,其类型为 Actor,有限状态机名称为 FsmName,加入 IdleState 和 MoveState 两个状态 IFsm<Actor> fsm2 = fsmComponent.CreateFsm<Actor>("FsmName", owner, new IdleState(), new MoveState()); |
例如:为 Actor 类创建一个名为 ActorFsm 的有限状态机,且加入站立(IdleState)和移动(MoveState)两个状态。
1 2 3 4 5 6 7 8 9 10 11 12 |
public class Actor { private IFsm<Actor> m_Fsm = null; public Actor() { FsmComponent fsmComponent = GameEntry.GetComponent<FsmComponent>(); // 参数传入有限状态机名称、拥有者和所有需要的状态 m_Fsm = fsmComponent.CreateFsm("ActorFsm", this, new IdleState(), new MoveState()); } } |
销毁有限状态机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 销毁有限状态机,持有者类型为 Actor,有限状态机名称为空 fsmComponent.DestroyFsm<Actor>(); // 销毁有限状态机,持有者类型为 Actor,有限状态机名称为空 fsmComponent.DestroyFsm(typeof(Actor)); // 销毁有限状态机,持有者类型为 Actor,有限状态机名称为 FsmName fsmComponent.DestroyFsm<Actor>("FsmName"); // 销毁有限状态机,持有者类型为 Actor,有限状态机名称为 FsmName fsmComponent.DestroyFsm(typeof(Actor), "FsmName"); // 销毁有限状态机,直接传入状态机实例引用 fsmComponent.DestroyFsm(fsm); |
切换有限状态机的状态
切换有限状态机状态只能在具体的状态中完成,不能直接由外部控制。
1 2 3 4 5 |
// 使用泛型参数切换状态 ChangeState<IdleState>(fsm); // 使用类型参数切换状态 ChangeState(fsm, typeof(IdleState)); |
有限状态机相关操作
1 2 3 4 5 6 7 8 9 10 11 |
// 启动有限状态机 fsm.Start<IdleState>(); fsm.Start(typeof(IdleState)); // 检查有限状态机是否拥有某个状态 bool hasState1 = fsm.HasState<IdleState>(); bool hasState2 = fsm.HasState(typeof(IdleState)); // 获取有限状态机状态 IdleState state1 = fsm.GetState<IdleState>(); IdleState state2 = (IdleState)fsm.GetState(typeof(IdleState)); |
参考手册
最佳实践
有限状态机的状态考虑使用引用池
考虑将诸如 new IdleState()、new MoveState() 使用引用池技术。
常见问题
创建有限状态机时提示已存在
如果同种有限状态机有很多实例,应当给有限状态机取 name 参数且不能重名。不带 name 参数的重载,相当于 name 为空。因此,当重复创建多个实例时,等同于重名。
有限状态机不工作
有限状态机模块需要被轮询才能正常调用事件处理函数,请确认正确初始化了 Game Framework。
另外请检查有限状态机是否已调用了 Start 方法。