什么是FSM
有限状态机(Finite-state machine)是一种用来进行对象行为建模的工具,其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。
在游戏中经常看到的一些AI,如敌人巡逻,巡逻过程中看到玩家就追击,追上了就攻击,追不上并且有了一定的距离就返回去继续巡逻。
Animator就是一个简单的状态机
如果不做任何处理的话,切换动画的话,一般就是直接animator.setXXX(),这样切换动画,耦合性高,可扩展性差,硬伤。几个动画还好,动画多了。。再来个什么判定,这种切换是很麻烦的
FSM整体框架(还没有制作一个完整的 Demo 只是一个大体的框架)
状态类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using System;
//状态类不需要继承monbehavior,制作成抽象类
public abstract class FsmState
{
//帮子类实现一下初始化
public FsmState()
{
Init();
}
public FSMStateID stateID;
//1.0映射表 保存的是达成相应条件对应的下一状态<trigger,state>
// 比如是 游戏当中的小怪没有发现玩家就站立不动->玩家走进之后发现玩家->攻击玩家
// 没有血量->玩家死亡
private Dictionary<FSMTriggerID, FSMStateID> map = new Dictionary<FSMTriggerID, FSMStateID>();
//2.0 条件列表<trigger> 通过条件列表来判断是否是达成
private List<FSMTrigger> triggers = new List<FSMTrigger>();
// 增加映射表和条件列表,删除的方法
public void AddMap(FSMTriggerID triggerid,FSMStateID stateID)
{
//判断一下,如果不含有这个键的话我们就去添加
if (!map.ContainsKey(triggerid))
{
map.Add(triggerid, stateID);
AddTrigers(triggerid);
}
//如果含有这个键的话 我们去修改一下就可以了
map[triggerid] = stateID;
}
public void AddTrigers(FSMTriggerID triggerID)
{
//如果 去实例化一个类
//使用反射机制(如果不是很明白的话 可以去看一下关于c#反射的视频)
triggers.Add(Activator.CreateInstance (Type.GetType(triggerID.ToString()+"Trigger"))as FSMTrigger);
}
//有增加的时候也会有删除映射列表
public void RemoveMap(FSMTriggerID triggerid)
{
if (map.ContainsKey(triggerid)) { map.Remove(triggerid); RemoveTriggers(triggerid); }
}
//删除条件列表
public void RemoveTriggers(FSMTriggerID triggerID)
{
//lamda表达式 在条件列表下边找到相同的条件 然后删除
triggers.Remove (triggers.Find(p => p.triggerID == triggerID))
;
}
//停止状态下通过条件列表来判断条件完成 然后进入映射表切换下一个状态
//Action :静止状态下,播放静止的动画
public abstract void Action(BaseFSM fsm);
/// <summary>
/// 初始化的方法
/// </summary>
public abstract void Init();
//添加一个检测的方法
int count = 0;
public void Detection(BaseFSM fsm)
{
count = triggers.Count;
//循环我们条件列表
for (int i = 0; i < count; i++)
{
//如果条件列表当中的条件达成,我们就要切换状态了
if (triggers[i].IsTrigger(fsm))
{
//切换状态
fsm.ChangeState(map[triggers[i].triggerID]);
}
}
}
}
//想要什么状态直接在这里边可以直接添加
public enum FSMStateID
{
/// <summary>
/// 静止状态
/// </summary>
Idle,
/// <summary>
/// 追逐状态
/// </summary>
Pursuit,
/// <summary>
/// 攻击状态
/// </summary>
Acttack,
/// <summary>
/// 死亡状态
/// </summary>
Death,
}
所需要的条件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class FSMTrigger
{
/// <summary>
/// 条件ID
/// </summary>
public FSMTriggerID triggerID;
//判断当前条件是否达成
public abstract bool IsTrigger(BaseFSM fsm);
public FSMTrigger()
{
Init();
}
protected abstract void Init();
}
public enum FSMTriggerID
{
/// <summary>
/// 发现玩家
/// </summary>
SawPlayer,
/// <summary>
/// 是否攻击
/// </summary>
IsAttack,
/// <summary>
/// 是否死亡
/// </summary>
isDeath,
/// <summary>
/// 没有血量
/// </summary>
NoDeath,
/// <summary>
/// 低血量
/// </summary>
lowHeath,
}
只有这一个脚本是挂在物体上边的
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 状态机
/// </summary>
public class BaseFSM : MonoBehaviour
{
/// <summary>
/// 当前状态ID
/// </summary>
public FSMStateID nowStateID;
/// <summary>
/// 当前状态
/// </summary>
public FsmState nowState;
/// <summary>
/// 当前默认状态的ID
/// </summary>
public FSMStateID defaultStateID;
/// <summary>
/// 当前默认状态
/// </summary>
public FsmState defaultState;
//状态的切换和状态行为的执行
public void Update()
{
nowState.Action(this);
nowState.Detection(this);
}
//状态列表
public List<FsmState> states = new List<FsmState>();
//切换状态
public void ChangeState(FSMStateID stateID)
{
if (stateID == nowStateID)
{
return;
}
if (stateID == defaultStateID)
{
//当前的=默认的
nowState = defaultState;
nowStateID = defaultStateID;
}
//都不是的情况下
else
{
//在状态库下边去寻找
nowState = states.Find(p=>p.stateID ==stateID);
nowStateID = nowState.stateID;
}
}
}
后期会更新一个具体的demo来更好的说明这个FSM的用法