一:
有限状态机用于管理游戏中对象的行为非常方便。
最简单的有限状态机实现方式
switch ()
case A:
xxx
通常switch块放到 对象的update方法中,每帧更新状态。
这种结构最大的问题是状态没有得到封装,而有限状态机中状态和状态之间是存在转化的,而转化的过程中,需要清理上个状态的数据,准备下个状态的数据,这样就会造成大量的冗余代码,以及对当前状态的混乱。
二:
具体的改善的做法:
抽象出分离状态机 , 状态, 以及转化三个概念。
状态机 包含一个当前状态, 所有状态, 包含update函数, 设置状态函数。
每个状态都有一个名字,以及enter exit update 函数, 以及初始化转化关系的函数。
一个转化是属于某个状态的,在特定条件下,将当前状态转化到下一个状态。
例如一个简单的状态机:
空闲状态 <----->选择状态-------->移动状态------>空闲状态
初始化状态机的过程就是:
增加空闲状态
增加选择状态
增加移动状态
初始化所有状态的转化关系
设定当前状态是空闲状态
三:
这时候如何触发状态转化呢?
在每个状态的update的过程中,都会检测有没有转化条件满足,如果有则退出当前状态,进入下一个状态。
这个转化是由状态内部自己检测来产生的,因此需要外部一直保持刺激信号,直到内部修改状态为止,这种行为是电平触发。
还有一种触发方式是边沿触发,即外部每变化一次,就触发一次状态变化。
电平触发存在的问题就是可能会丢失事件。
四:
可能存在这样一种情况:
一个事件发生导致A对象的状态变化,B对象的状态变化,这两个变化可能会都修改相同的对象的属性,这时候,应该确保逻辑上的先后顺序,或者保证只修改属于本对象的那些对象的属性。
五:层次状态机
对于一个复杂的对象可能有大量的状态,一种简化状态数量的方法就是建立装他的层次:
例如法师的攻击状态:
法师是连锁闪电攻击,攻击完初始目标之后,会寻找下一个目标, 找到则攻击,否者退出攻击状态;
而这三个子状态都是属于攻击状态这个大状态的。
因此每个状态需要增加:
当前状态所在层次
孩子属性所有的子状态
初始状态
这样状态的进入,退出 和 转化时,就要相应的考虑子状态的问题:
进入一个状态 如果有初始状态则进入初始状态, 递归初始化状态。
退出一个状态,通常是转化到另外一个状态,则需要退出到下一个状态的相应的层级。
六: 状态机可配置action
一个状态下的行为可能因为当前上下文不同,而有不同。
例如一个对象受到攻击之后, 根据攻击对象不同,可能产生不同的效果,例如如果攻击方是骑士,那么可能会被击退一格,攻击方是忍者,可能就会交换彼此的位置。
同样一个人攻击另外一个对象,根据被攻击者不同也会产生不同的效果,例如如果是我方,那么交换位置,如果是敌方则产生伤害。
因此给状态添加action 属性:
action 包含 enter exit update 函数
通过设定目标对象某个状态下的action, 来达到同一状态,不同表现行为的目的!
这种设定需要在状态转化之前完成。