关于 有限状态机 的思考和理解 (游戏开发)
小记一下对状态机设计的思考,直接跳到思考部分即可。
设计有限状态机
-
状态
定义一个抽象基类 AbstractState,任意状态都有 进入状态、执行状态、退出状态 三个阶段,无需理会如何进入。
任一状态都实现基类,便于管理。 -
状态的切换条件
定义一个抽象基类 AbstractTrigger,任意条件都只需返回Bool即可。
当从Idle -> Walk状态时必定需要一个条件,比如Input、AI或者技能影响控制,将条件从状态本身中抽出,此时条件还可以被复用。 -
有限状态机管理类(FSMMgr)
存储和管理状态的转换。
定义一个Map<AbstractState, List<AbstractTrigger, AbstractState>>,存储所有状态的转换逻辑。在Update中遍历当前状态可触发的所有条件。 -
状态机的逻辑管理
可以通过代码或者文本控制的方式,
例如FSMMgr.Push(IdleState, OnDieTrigger, DieState)
或者在文本配置表中定义逻辑,并在启动时读取和解析序列化。要做到这种效果,最好规范状态和切换条件的命名。IdleState: OnDieTrigger: DieState
思考
我强迫症总觉得状态机的设计很不符合规范,所以深入思考了一下状态机在面向对象设计中的规范姓。记录一下我的思路变化。
-
一个有限状态机应该考虑到的内容
外部系统、状态机管理类、状态切换条件、状态 -
它们的关系是怎样的?
- 状态和条件应该是独立的、只被依赖使用的。
但是由于状态是对某个对象(称之为被服务对象?)进行控制,所以必定不能满足此条件,状态和条件只能改为 依赖某个对象的,其必定是耦合的。 - 状态机管理与状态和条件之间应该是模糊的。
即不用理会具体状态,只需对抽象基类负责即可。同时负责检查条件和切换状态。 - 外部系统应该使用状态机管理类,同时往管理类中添加条件和状态。
也就是说,这整个系统必然是耦合的。
- 状态和条件应该是独立的、只被依赖使用的。
-
这样子合理吗?
- 状态切换本身就是高耦合的,通过状态机降低耦合即可。
- 将状态和条件的具体逻辑抽出,被管理的对象只需对状态切换逻辑负责即可。
- 状态也应该具有被管理对象状态的引用,因为状态就是对被管理对象进行操作的。
- 因此状态机应该限定为某个类或某个类的子孙类服务,甚至将状态机定义为被服务对象的一部分(必定为依赖关系或关联关系,而且大概率是互相依赖、互相关联,)。即将有限状态机定义为角色有限状态机。