【Unity2DMobileGame_PirateBomb11】—— 使用有限状态机实现敌人的AI状态

551 阅读4分钟

文章目录

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()方法来切换这两个状态就可以实现状态中单独实现的方法。同时用这样的方法可以实现无限的状态拓展。