游戏AI状态机:基类虚方法能否中止子类重写方法的执行?
游戏AI状态机:高优先级状态切换的执行终止方案
问题背景
在游戏AI状态机实现中,EatState是优先级最高的状态,可从多数状态直接切换至该状态。为避免重复定义切换逻辑,计划在所有状态的父类BaseState中统一实现该逻辑。BaseState包含4个需子类重写的抽象方法:
Enter()UpdateLogic():负责检查状态切换条件UpdatePhysics():处理移动等物理操作Exit()
当前实现存在逻辑覆盖问题:基类UpdateLogic中实现了EatState的切换检查,但子类重写时调用base.UpdateLogic()后,自身的切换条件若满足会覆盖基类的状态切换结果,导致高优先级的EatState被低优先级状态顶替,示例代码如下:
public class BaseState { public virtual void UpdateLogic() { // 假设条件满足,切换至EatState if (someCondition){ changeState("EatState"); } } } public class MoveState : BaseState { public override void UpdateLogic() { base.UpdateLogic(); // 此处条件满足时,状态会被重新切换为FightState,覆盖基类的结果 if (someOtherCondition){ changeState("FightState"); } } }
核心问题解决方案
要实现基类虚方法执行时中止子类重写方法的后续执行,可通过以下三种方案实现:
1. 基于返回值的流程控制
修改基类UpdateLogic的返回值为布尔类型,用于标记是否已触发高优先级状态切换,子类根据返回值决定是否继续执行自身逻辑:
public class BaseState { public virtual bool UpdateLogic() { // 检查EatState切换条件 if (someCondition) { changeState("EatState"); return true; // 返回true表示已触发高优先级切换,子类无需继续执行 } return false; // 未触发切换,子类可执行自身逻辑 } } public class MoveState : BaseState { public override bool UpdateLogic() { bool hasSwitchedToHighPriority = base.UpdateLogic(); if (hasSwitchedToHighPriority) { return true; // 基类已完成高优先级切换,直接终止后续逻辑 } // 子类自身的状态切换逻辑 if (someOtherCondition) { changeState("FightState"); return true; } return false; } }
该方案需要子类遵守约定,主动检查基类的返回值来控制流程。
2. 基于状态标记的流程控制
在BaseState中添加受保护的状态标记字段,基类触发切换时设置标记,子类执行自身逻辑前检查该标记:
public class BaseState { protected bool _hasSwitchedState = false; public virtual void UpdateLogic() { _hasSwitchedState = false; if (someCondition) { changeState("EatState"); _hasSwitchedState = true; } } } public class MoveState : BaseState { public override void UpdateLogic() { base.UpdateLogic(); if (_hasSwitchedState) { return; // 基类已切换状态,终止后续执行 } if (someOtherCondition) { changeState("FightState"); } } }
该方案通过标记传递状态信息,同样需要子类主动检查标记以终止执行。
3. 模板方法模式重构(推荐)
将UpdateLogic拆分为基类控制的固定流程和子类实现的自定义逻辑部分,基类先执行高优先级状态检查,仅当未触发切换时才调用子类的自定义逻辑:
public abstract class BaseState { public void UpdateLogic() { // 优先执行高优先级状态检查 if (CheckHighPriorityStates()) { return; // 已切换高优先级状态,直接终止流程 } // 未触发高优先级切换,执行子类自定义逻辑 CheckCustomStates(); } // 基类实现高优先级状态检查(如EatState) protected virtual bool CheckHighPriorityStates() { if (someCondition) { changeState("EatState"); return true; } return false; } // 子类重写该方法实现自身的状态切换逻辑 protected abstract void CheckCustomStates(); // 实现其他抽象方法 public abstract void Enter(); public abstract void UpdatePhysics(); public abstract void Exit(); } public class MoveState : BaseState { protected override void CheckCustomStates() { if (someOtherCondition) { changeState("FightState"); } } // 实现其他抽象方法 public override void Enter() { /* ... */ } public override void UpdatePhysics() { /* ... */ } public override void Exit() { /* ... */ } }
该方案从架构层面固定了执行顺序,子类无需关心高优先级状态的逻辑,彻底避免了人为失误导致的逻辑覆盖问题,是最健壮的实现方式。
内容的提问来源于stack exchange,提问作者vandermies
相关产品推荐
相关产品推荐

