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
相关产品推荐
相关产品推荐

