根据上述行为,可以设计如图所示的状态装转换图。坦克有逻辑、进攻和逃跑三种状态,在逻辑状态下,如果发现了敌人(敌人出现在坦克的视角范围内)则会变成进攻状态;在进攻状态下,如果丢失了目标(目标被摧毁或离开视角范围)则会回到巡逻状态;交战过程中,如果坦克的hp(生命值)小于指定值,则逃跑,直到远离目标继续巡逻。
如果不考虑设计模式,状态机可以简单地用ifelse语句来实现。有限状态机的特点是输出(转换的状态)只由当前状态和输入(满足的条件)来确定,有着明显的逻辑关系,代码结构如下:
void Update()
{
target = 搜寻目标();
if (坦克状态 == 巡逻)
{
if (target != null)
坦克状态 = 进攻;
else
处理巡逻状态();
}
else if (坦克状态 == 进攻)
{
if (target == null)
坦克状态 = 巡逻;
else if (tank.hp < 30) 坦克状态 = 逃跑;
else 处理进攻状态();
}
else if(坦克状态 == 逃跑)
{
if (target == null || 远离(target))
坦克状态 = 巡逻;
else
处理逃跑状态();
}
}
上述状态机定义了坦克巡逻、进攻和逃跑三项策略,并规定了切换策略的条件。然而状态机并没有告诉坦克在各种状态下应该做什么事情,比如:巡逻状态下怎样走到指定的位置,进攻状态下又该怎样靠近敌人,炮塔如何瞄准对手等,这便涉及了第二层状态机。以进攻以进攻状态为例,坦克要处理移动和开炮两件事情。
如同进攻状态,巡逻和逃跑也对应着“炮塔状态机”和“移动状态机”两种情形(见下图)。每一层状态机相互独立,负责自己的功能。例如,当坦克处于进攻状态时,“处理进攻状态的方法”只需要告知“移动状态机”目的地的坐标即可,至于怎样移动到目的地则由“移动状态机”全权负责。