You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity3D抽象敌人状态机实现:派生类参数传递报错问题

敌人有限状态机派生类参数匹配问题的解决方案

问题背景

在实现游戏敌人有限状态机时,基类EnemyState的方法(如EnterState、UpdateState)参数为EnemyStateManager,但派生状态类(如SoldierIdleState)希望使用派生的SoldierStateManager作为参数重写基类方法,导致报错:

'SoldierIdleState.EnterState(SoldierStateManager)': no suitable method found to override

原因是C#中重写方法必须与基类方法的签名完全一致,包括参数类型。即使SoldierStateManager是EnemyStateManager的派生类,参数类型不同也无法构成重写。

基类代码

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) {}
}

派生类代码

public class SoldierStateManager : EnemyStateManager
{
    public SoldierIdleState IdleState = new SoldierIdleState();
    public SoldierDeadState UnconsciousState = new SoldierUnconsciousState();

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

        currentState = IdleState;
        currentState.EnterState(this);
    }
}
public class SoldierIdleState : EnemyState
{
    float moveSpeed = 2f;

    public override void EnterState(SoldierStateManager soldier) 
    {
        base.EnterState(soldier);
        soldier.SetVelocity(moveSpeed);
    }

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

    public override void UpdateState(SoldierStateManager soldier) 
    {
        base.UpdateState(soldier);
        if (soldier.health <= 0)
        {
            soldier.SwitchState(soldier.UnconsciousState);
        }
    }
}
public class SoldierUnconsciousState : EnemyState
{
    float moveSpeed = 0f;
    float unconsciousDuration = 5f;

    public override void EnterState(SoldierStateManager soldier) 
    {
        base.EnterState(soldier);
        soldier.SetVelocity(moveSpeed);
    }

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

    public override void UpdateState(SoldierStateManager soldier) 
    {
        base.UpdateState(soldier);
        if (Time.time >= stateStartTime + unconsciousDuration)
        {
            soldier.SwitchState(soldier.IdleState);
        }
    }
}

解决方案

方案1:保留基类方法签名,内部强转参数

这种方式无需修改基类结构,直接在派生状态类中通过类型检查和强转使用派生管理器:

修改SoldierIdleState:

public class SoldierIdleState : EnemyState
{
    float moveSpeed = 2f;

    public override void EnterState(EnemyStateManager enemy) 
    {
        base.EnterState(enemy);
        // 先检查类型再强转,避免类型错误
        if (enemy is SoldierStateManager soldier)
        {
            soldier.SetVelocity(moveSpeed);
        }
    }

    public override void ExitState(EnemyStateManager enemy) 
    {
        base.ExitState(enemy);
        if (enemy is SoldierStateManager soldier)
        {
            // 针对SoldierStateManager的退出逻辑
        }
    }

    public override void UpdateState(EnemyStateManager enemy) 
    {
        base.UpdateState(enemy);
        if (enemy is SoldierStateManager soldier)
        {
            if (soldier.health <= 0)
            {
                soldier.SwitchState(soldier.UnconsciousState);
            }
        }
    }
}

修改SoldierUnconsciousState:

public class SoldierUnconsciousState : EnemyState
{
    float moveSpeed = 0f;
    float unconsciousDuration = 5f;

    public override void EnterState(EnemyStateManager enemy) 
    {
        base.EnterState(enemy);
        if (enemy is SoldierStateManager soldier)
        {
            soldier.SetVelocity(moveSpeed);
        }
    }

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

    public override void UpdateState(EnemyStateManager enemy) 
    {
        base.UpdateState(enemy);
        if (enemy is SoldierStateManager soldier)
        {
            if (Time.time >= stateStartTime + unconsciousDuration)
            {
                soldier.SwitchState(soldier.IdleState);
            }
        }
    }
}

适用场景:小规模敌人类型,快速实现需求,无需复杂架构调整。


方案2:使用泛型基类实现类型强绑定

通过泛型让状态类与对应的管理器类强绑定,从根源避免类型转换:

步骤1:泛型化EnemyState基类

public class EnemyState<T> : MonoBehaviour where T : EnemyStateManager
{
    protected float stateStartTime;

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

    public virtual void ExitState(T enemy) {}

    public virtual void UpdateState(T enemy) {}
}

泛型约束where T : EnemyStateManager确保传入的类型必须是EnemyStateManager或其派生类。

步骤2:修改派生状态类继承泛型基类

public class SoldierIdleState : EnemyState<SoldierStateManager>
{
    float moveSpeed = 2f;

    public override void EnterState(SoldierStateManager soldier) 
    {
        base.EnterState(soldier);
        soldier.SetVelocity(moveSpeed);
    }

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

    public override void UpdateState(SoldierStateManager soldier) 
    {
        base.UpdateState(soldier);
        if (soldier.health <= 0)
        {
            soldier.SwitchState(soldier.UnconsciousState);
        }
    }
}
public class SoldierUnconsciousState : EnemyState<SoldierStateManager>
{
    float moveSpeed = 0f;
    float unconsciousDuration = 5f;

    public override void EnterState(SoldierStateManager soldier) 
    {
        base.EnterState(soldier);
        soldier.SetVelocity(moveSpeed);
    }

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

    public override void UpdateState(SoldierStateManager soldier) 
    {
        base.UpdateState(soldier);
        if (Time.time >= stateStartTime + unconsciousDuration)
        {
            soldier.SwitchState(soldier.IdleState);
        }
    }
}

步骤3:调整SoldierStateManager适配泛型状态

public class SoldierStateManager : EnemyStateManager
{
    public SoldierIdleState IdleState = new SoldierIdleState();
    public SoldierUnconsciousState UnconsciousState = new SoldierUnconsciousState();
    // 修改currentState类型为泛型状态
    protected new EnemyState<SoldierStateManager> currentState;

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

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

    // 重写Update方法,调用泛型状态的UpdateState
    new void Update()
    {
        currentState.UpdateState(this);
    }

    // 重写SwitchState方法,适配泛型状态
    public void SwitchState(EnemyState<SoldierStateManager> newState)
    {
        currentState.ExitState(this);
        currentState = newState;
        currentState.EnterState(this);
    }
}

如果需要更彻底的泛型化,可以将EnemyStateManager也改为泛型类:

public class EnemyStateManager<T> : MonoBehaviour where T : EnemyStateManager<T>
{
    protected EnemyState<T> currentState;
    public float health;

    public virtual void Start() {}

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

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

    public virtual void Attack() {}

    public virtual void Die() {}

    public virtual bool CheckWall() {}

    public virtual bool CheckLedge() {}

    public void SetVelocity(float speed) {}
}

此时SoldierStateManager的写法简化为:

public class SoldierStateManager : EnemyStateManager<SoldierStateManager>
{
    public SoldierIdleState IdleState = new SoldierIdleState();
    public SoldierUnconsciousState UnconsciousState = new SoldierUnconsciousState();

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

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

适用场景:需要长期维护、扩展多种敌人类型的项目,追求类型安全和架构优雅。


内容的提问来源于stack exchange,提问作者darkcrustbread

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 20:39:56