这次写一个简单的AI巡逻,与上次思路相同,也是写枚举、状态基类、管理类,因为还是用的鹿的模型动画,所以只有跑、站立和死亡三种状态,这次巡逻就不用动画的状态机了,只把Animator
的X设置为1就好了,先来看看演示吧。
GIF太小了凑合看吧,压制到144p才能传上来。还有一个攻击的状态,因为没动画所以就log了一下。正文开始。
与之前一样,先确定状态,有巡逻、攻击、追逐、返回四种状态,所以先写个枚举列出来:
public enum FSMChaseState
{
Chase,
Return,
Patrol,
Attack
}
然后再写个巡逻的基类。
public abstract class FSMChase<T> : FSMBase<T> where T : struct, Enum
{
protected FSMChase(FSMManagerBase<T> manager) : base(manager)
{
}
}
因为巡逻肯定要判定距离,而距离需要两个vec3,所以需要传入两个transform先放着,声明两个字段储存。
protected readonly Transform playerTransform;
protected readonly Transform monsterTransform;
protected FSMChase(FSMManagerBase<T> manager, Transform playerTransform, Transform monsterTransform) : base(manager)
{
this.playerTransform = playerTransform;
this.monsterTransform = monsterTransform;
}
基类写好了再写这四种状态
public class FSMChasePlayer: FSMChase<FSMChaseState>
{
public FSMChasePlayer(FSMManagerBase<FSMChaseState> manager, Transform playerTransform, Transform monsterTransform)
: base(manager, playerTransform, monsterTransform)
{
ClassState = FSMChaseState.Chase;
}
public override FSMChaseState ClassState {
get; protected set; }
public override void OnEnter()
{
}
public override void OnUpdate()
{
}
public override void OnFixedUpdate()
{
}
public override void OnExit()
{
}
}
//只是先继承还不实现,所以下面的类大同小异,就不写出来了
//FSMAttack
//FSMMove2LastPos
//FSMMove
画图时间又到了。
大概的逻辑就是这样了,关系有点乱,看图可能不清楚,但写着写着就豁然开朗了。这次做的算是简约状态,还可以再加入:从返回状态再次回到追逐状态,鉴于之前没做就不再写了。
先从最简单的attack状态写,之前做了一个矩阵攻击的类加进来了,这里也可以用debug.log代替。
public class FSMAttack : FSMChase<FSMChaseState>
{
//private readonly Transform _attackArea;
public FSMAttack(FSMManagerBase<FSMChaseState> manager/*, Transform attackArea*/, Transform player,
Transform monsterTransform) : base(manager, player, monsterTransform)
{
//_attackArea = attackArea;
ClassState = FSMChaseState.Attack;
}
public sealed override FSMChaseState ClassState {
get; protected set; }
public override void OnEnter()
{
Debug.Log("攻击了玩家,攻击结果为" + Detection.RectangleAttackDetection(_attackArea, playerTransform, Vector3.one * 0.5f));//用Debug.Log(true);代替即可
manager.SetCurrentState(manager.GetState(FSMChaseState.Chase));
}
public override void OnUpdate()
{
}
public override void OnFixedUpdate()
{
}
public override void OnExit()
{
}
}
只需要攻击完就转换到chase状态即可,非常简单。接下来再写move状态。
move状态可以传递移动点位,也可以传递一片区域,区域内随机生成点位移动就好,这里采取的是传递移动点位,传递一个List<Transform>的数组就可以,声明私有字段储存。因为是数组采取遍历下标的方式来获取移动点位,移动一次下标加一,所以不采用for,直接声明私有字段_index储存下标。另外声明一个移动速度Speed。
private readonly List<Transform> _list;
private int _index;
private const float Speed =