Search code examples
c#overridingstate-machine

Can a virtual method abort the execution of the abstract method overriding it?


I am implementing a state machine for game AI, and one of the states —EatState— must be accessible from almost every other state and have priority over the rest. Instead of defining this transition in all the states, I was thinking of implementing it in a superclass BaseState from which all the other extend.

BaseState has 4 abstract methods that the subclasses override, which are

  1. Enter()
  2. UpdateLogic() -> check for the conditions to transitionate from one state to another...
  3. UpdatePhysics() -> apply movement and others
  4. Exit()

The problem I find if I implement the check for the transition to the EatState in the superclass, and then call the particular checks of the subclass, is that the latter results override the ones obtained in the superclass:

public class BaseState {
   public virtual void UpdateLogic() {
      // Let's imagine the condition is met and the state is changed
      if (someCondition){
         changeState("EatState");
      }
   }
}


public class MoveState : BaseState {
   public override void UpdateLogic() {
      base.UpdateLogic();
      // But here the condition is also met, so the state is re-changed.
      if (someOtherCondition){
         changeState("FightState");
      }
   }
}

I realise that I can just move the prioritary state check to the bottom of the method in order to override the result of the subclass:

public class MoveState : BaseState {
   public override void UpdateLogic() {
      if (someOtherCondition){
         changeState("FightState");
      }
      base.UpdateLogic();
   }
}

or that I could make the check in the subclass more restrictive, but this question kept me wondering about this:

Is there a way to avoid the execution of an override method once the base virtual method is being executed in the superclass? I am looking for something that would act like a return statement that could somehow propagate from the superclass to the subclass and abort the latter execution.


Solution

  • You can control this behavior by returning bool instead of void to indicate if the base class behavior was used.

    public class BaseState
    {
        public virtual bool UpdateLogic()
        {
            // Let's imagine the condition is met and the state is changed
            if (someCondition)
            {
                changeState("EatState");
                return true;
            }
            
            return false;
        }
    }
    
    public class MoveState : BaseState
    {
        public override bool UpdateLogic()
        {
            var wasUpdatedInBase = base.UpdateLogic();
            // But here the condition is also met, so the state is re-changed.
            if (!wasUpdatedInBase && someOtherCondition)
            {
                changeState("FightState");
            }
        }
    }