文章目录
1.敌人状态分析
Finite State Machine
有限状态机可以很好的拓展代码,状态机的写法有很多,比如if-else,switch-case,这里使用抽象类继承的方式来写状态机。
可以在后续添加一个新的状态的时候,可以另外创建一个单独的代码来继承最基本的类,然后对功能进行拓展。
当前敌人有两种状态
1.巡逻的状态,进入巡逻状态,在A,B两个点之间来回巡逻,一旦发现Player或者Bomb切换到攻击的状态
2.进入攻击状态后,可以追踪游戏目标,进行攻击模式的筛选,攻击Player或者吹灭炸弹。
2.创建敌人的基本状态
创建EnemyBaseState脚本,它不需要挂在到任何场景物体上,所以不继承MonoBehaviour。
不管是巡逻状态还是攻击状态,都具有两个时机点,当进入状态的时候需要实现一些基本功能,当在进入状态在当前状态下Update的每一帧当中需要执行的一些方法。
进入状态之后仍需要调用敌人的和一些参数,所以需要把Enemy对象当作参数传进方法中。
public abstract class EnemyBaseState
{
public abstract void EnterState(Enemy enemy);
public abstract void OnUpdate(Enemy enemy);
}
3.为人物创建两个不同的状态
3.1 巡逻状态
进入巡逻状态一开始需要先切换目标点,不需要在Enemy的Start中进行切换,而是在巡逻状态脚本下进行切换。同样的Update中的方法写在OnUpdate中
using UnityEngine;
public class PatrolState : EnemyBaseState
{
public override void EnterState(Enemy enemy)
{
// 一进入状态切换巡逻的目标点
enemy.SwitchPoint();
}
public override void OnUpdate(Enemy enemy)
{
// 每一帧把不断的循环 无限趋近于目标点 当前敌人的坐标以及当前敌人的目标点
if (Mathf.Abs(enemy.transform.position.x - enemy.targetPonit.position.x) < 0.01f)
enemy.SwitchPoint();
enemy.MoveToTarget();
}
此时状态机的函数方法写在了两个不同的类中,并且PatrolState并没有挂载在敌人身上。
3.2 在Enemy中实现抽象类状态机的功能
增加状态机的类型变量
/// 敌人的当前的状态
private EnemyBaseState _currentState;
_currentState
当前的状态有两种,一种是巡逻状态,另一种是攻击状态。
需要写一个函数的方法用来切换到哪一个状态。这里需要获取巡逻状态的对象和攻击状态的对象,把这个对象传参进TransitionToState()方法中,使当前状态=传入的对象,传入之后调用它本身的EnterState方法进人该状态。
/// 切换状态的方法
public void TransitionToState(EnemyBaseState state)
{
// 切换状态 当前状态 = 传入的状态
_currentState = state;
// 切换之后敌人进入当前状态
_currentState.EnterState(this);
}
获取需要传入参数的对象,这里先获取巡逻的,攻击的对象还没写。
// 获取巡逻状态的对象
public PatrolState patrolState = new PatrolState();
游戏在一开始执行敌人应该是巡逻状态,并且在Update中一直保持来回巡逻。
void Start()
{
// 开始游戏直接进入巡逻状态
TransitionToState(patrolState);
}
void Update()
{
// 当前敌人执行当前状态
_currentState.OnUpdate(this);
}
定义了一个当前状态的类型是一个抽象类,该抽象类继承的子类有两种不同的状态,使用TransitionToState方法来切换两种不同的状态,获得状态变量赋给当前状态,使它在游戏一开始的时候就执行进入函数状态的方法,并且保持在Update中一直执行来回移动。
3.3 添加攻击的状态
前面使用抽象类已经实现了在Enemy中添加巡逻的状态,用同样的方式添加攻击的状态。
public class AttackState : EnemyBaseState
{
public override void EnterState(Enemy enemy)
{
// TODO 刚进入攻击状态
}
public override void OnUpdate(Enemy enemy)
{
// TODO 攻击状态下一直注意人物 实现追击,攻击等方法
}
}
同样的需要在Enemy中添加攻击状态的实例对象。
// 获取攻击状态的对象
public AttackState attackState = new AttackState();
接下来只需要使用TransitionToState()方法来切换这两个状态就可以实现状态中单独实现的方法。同时用这样的方法可以实现无限的状态拓展。