在Unity3D中创建抽象敌方状态机

nlejzf6q  于 2023-03-30  发布在  其他
关注(0)|答案(2)|浏览(122)

我正在尝试为我的游戏中的敌人行为实现一个可重用的有限状态机,并且正在努力弄清楚如何将派生类作为参数传递。下面是我为敌人可以拥有的不同状态提供的两个基本模板类,以及在有限状态机实现中充当上下文的状态管理器。状态管理器脚本附加到敌人游戏对象,并且应该包含所有敌人使用的常见行为和数据。

public class EnemyState : MonoBehaviour
{
    protected float stateStartTime;

    public virtual void EnterState(EnemyStateManager enemy)
    {
        stateStartTime = Time.time;
    }

    public virtual void ExitState(EnemyStateManager enemy) {}

    public virtual void UpdateState(EnemyStateManager enemy) {}
}
public class EnemyStateManager : MonoBehaviour
{
    protected EnemyState currentState;
    public float health;

    public virtual void Start() {}

    void Update()
    {
        currentState.UpdateState(this);
    }

    public void SwitchState(EnemyState newState)
    {
        currentState.ExitState(this);
        currentState = newState;
        currentState.EnterState(this);
    }

    public virtual void Attack() {}

    public virtual void Die() {}

    public virtual bool CheckWall() {}

    public virtual bool CheckLedge() {}

    public void SetVelocity(float speed) {}
}

我的目的是创建从上述类派生的具体类,以加快设计不同的敌人AI行为,这样我就不必重写基本模板中已经包含的共同敌人逻辑,并且可以在不同类型的敌人之间重用。
一个一个二个一个一个一个三个一个一个一个一个一个四个一个
我被卡住了,因为当我尝试实现上面的想法时,我在具体的State类中得到了错误,例如:'SoldierIdleState.EnterState(SoldierStateManager)': no suitable method found to override在我试图从基类重写的所有方法中,我猜是因为EnterState()的方法签名需要EnemyStateManager类型,并且不接受SoldierStateManager,即使它是从EnemyStateManager派生的。
有没有什么方法可以将EnemyStateManager子类传递到派生方法中,因为我对C#和继承很陌生,所以我很感激任何关于如何完成这项工作的指导。

km0tfn4u

km0tfn4u1#

重写方法必须与重写的基方法具有相同的签名。
从你的基类:

public virtual void EnterState(EnemyStateManager enemy)

从您的子类:

public override void EnterState(SoldierStateManager soldier)

你需要保持EnemyStateManager作为参数类型。在用例方面,你确实会传递一个SoldierStateManager类型的参数,因为它继承自EnemyStateManager,因此是预期的类型。

public override void EnterState(EnemyStateManager soldier)

用例的简单示例:

SoldierUnconsciousState test_case = new();
SoldierStateManager new_state = new();
test_case.EnterState(new_state); // new_state is both of type SoldierStateManager and EnemyStateManager
eqqqjvef

eqqqjvef2#

我最终得到了我想要的东西,因为我不再需要将状态管理器作为参数传递,而是通过构造函数传递它们。出于某种原因,构造函数将接受派生的状态管理器类作为有效参数,现在我创建的任何子状态类都可以访问SoldierStateManager中的字段。

public abstract class EnemyState
{
    protected EnemyStateManager entity;
    protected float stateStartTime;

    public EnemyState(EnemyStateManager enemy)
    {
        this.entity = enemy;
    }

    public virtual void EnterState()
    {
        stateStartTime = Time.time;
    }

    public virtual void ExitState() { }

    public virtual void UpdateState() { }
}
public class SoldierIdleState : EnemyState
{
    protected SoldierStateManager soldier;
    float moveSpeed = 2f;

    public SoldierIdleState(SoldierStateManager enemy) : base(enemy)
    {
        soldier = enemy;
    }
    public override void EnterState() 
    {
        base.EnterState(soldier);
        soldier.SetVelocity(moveSpeed);
    }

    public override void ExitState() 
    {
        base.ExitState();
    }

    public override void UpdateState() 
    {
        base.UpdateState(soldier);
        if (soldier.health <= 0)
        {
            soldier.SwitchState(soldier.UnconsciousState);
        }
    }
}
public class SoldierStateManager : EnemyStateManager
{
    public SoldierIdleState IdleState { get; private set; }
    public SoldierUnconsciousState UnconsciousState { get; private set; }

    public override void Start()
    {
        base.Start();

        IdleState = new SoldierIdleState(this);
        UnconsciousState = new SoldierUnconsciousStateState(this);

        currentState = IdleState;
        currentState.EnterState();
    }
}

相关问题