FSM模块简介
FSM有限状态机用于模拟一切可以抽象为有限状态机结构的业务逻辑,类似于角色动画、怪物AI、任意有独立逻辑的个体等。
使用FSM
自定义状态
使用FSM前,必须自定义状态,任何自定义状态,可用于任何FSM使用,自定义状态类必须满足以下条件:
1.继承至FiniteState
2.标记特性FiniteStateName
推荐使用快捷创建方式:
Project界面右键 -> Create -> HTFramework -> FiniteState Script
如下图,我自定义了一个名为IdleState的状态:(相应的实现函数将在此状态的对应时机调用)
/// <summary>
/// 闲置状态
/// </summary>
[FiniteStateName("Player/闲置")]
public class IdleState : FiniteState
{
/// <summary>
/// 初始化
/// </summary>
public override void OnInit()
{
}
/// <summary>
/// 进入状态
/// </summary>
public override void OnEnter()
{
}
/// <summary>
/// 离开状态
/// </summary>
public override void OnLeave()
{
}
/// <summary>
/// 切换状态的动机
/// </summary>
public override void OnReason()
{
}
/// <summary>
/// 状态帧刷新
/// </summary>
public override void OnUpdate()
{
}
/// <summary>
/// 状态终结
/// </summary>
public override void OnTermination()
{
}
}
创建新的FSM
选中任意物体,为其添加FSM脚本后,其便已作为一个单独的有限状态机存在,这里为Player添加一个FSM脚本:
Component -> HTFramework -> FSM
为FSM附加状态
修改FSM的Name为Player001,注意名字不能重复!
点击下方的Add State按钮,可以附加我们创建的自定义状态到此FSM:(注意:附加状态时的路径为FiniteStateName特性指定的路径)
FSM存在至少一个状态后,会自动指定第一个附加的状态为初始状态,可以直接点击Set Default按钮重新设置初始状态:
为FSM使用自定义数据
很多时候,不同的FSM拥有不同的数据,为FSM指定自定义数据是一个不错的选择。
如何使用自定义数据类:新建类,使其继承至FSMData。
如下,新建Player的数据类PlayerData:
public class PlayerData : FSMData
{
//攻击力
public int AttackPower;
//防御力
public int DefensePower;
//速度
public float Speed;
public override void OnInit()
{
}
}
然后直接在Player的FSM面板为其指定数据类为PlayerData:
指定后,状态机Player001内的所有状态都将拥有一个共同的数据类对象PlayerData,访问数据的方法非常简单,如下:
[FiniteStateName("Player/攻击")]
public class AttackState : FiniteState
{
/// <summary>
/// 初始化
/// </summary>
public override void OnInit()
{
// OwnStateMachine 为此状态当前所属状态机
PlayerData data = OwnStateMachine.CurrentData as PlayerData;
GlobalTools.LogInfo("攻击力:" + data.AttackPower);
GlobalTools.LogInfo("防御力:" + data.DefensePower);
GlobalTools.LogInfo("速度:" + data.Speed);
}
}
切换状态
FSM启动后将会进入默认状态,此时将切换到其他状态的动机写到OnReason方法内是一个明智的决定,在判断时机成熟时,切换状态的方法如下:
/// <summary>
/// 切换状态的动机
/// </summary>
public override void OnReason()
{
//开始攻击
if (IsAttack)
{
OwnStateMachine.SwitchState<AttackState>();
}
}
也可以在状态机外部切换状态:
void Update ()
{
//开始攻击
if (IsAttack)
{
// GetFSMByName 通过名称获取状态机
Main.m_FSM.GetFSMByName("Player001").SwitchState<AttackState>();
}
}
运行时动态附加状态
FSM支持运行时动态附加状态,比如角色002是一个NPC,其在初始时不具备攻击状态AttackState,之后由于剧情需要为其开放攻击模式,则可以动态为其附加AttackState:
FSM fsm = Main.m_FSM.GetFSMByName("Player001");
fsm.AppendState<AttackState>();
fsm.SwitchState<AttackState>();
运行时动态终结状态
FSM支持运行时动态终结状态,比如角色002由于被主角打败已经彻底失去了战斗力,此时可以直接终结其攻击状态AttackState,则后续其所有妄图攻击的请求都会被阻断:
FSM fsm = Main.m_FSM.GetFSMByName("Player001");
fsm.TerminationState<AttackState>();