如何编写一个状态机,这样我就不必使用 99% 相似的代码来复制状态?

How to write a state machine so that I don't have to duplicate states with 99% similar code?

我正在制作一个城市管理游戏,其中的工人完全由状态机控制。我有一个“问题”,我发现自己重写了很多 99% 相似的状态。通常一些状态的唯一区别是它完成后应该进入哪个状态。

例如,下面的状态是用于传送资源的,这是所有职业都会做的事情,但是我为每个职业写了一个特定的状态,因为它们在完成时都会导致不同的状态。

public class BakerDeliverGrainState : BaseWorkerState, IState
{
    public void Enter()
    {
        //Go to storage
        SetDestination(storage.position);
    }

    public void Execute()
    {
        if (unit.ReachedDestination())
        {
            //Reached destination, state completed
            storage.Store(unit.TakeResource());
            unit.stateMachine.ChangeState(new BakerWorkState(unit)); //This is the line that seperates the states. For example a blacksmith will go to "BlacksmithWorkState", and so on.
        }
    }

    public void Exit()
    {
        
    }
}

有什么方法可以在构造函数中传递要更改到的状态吗?或者我可以通过其他方式调整我的设计,而不需要我重新编写那么多代码。

将匿名函数传递给将创建新状态的构造函数怎么样?

public class BaseWorkerState
{
   protected Func<Unit, IState> createCompletedState;
  
   // Use this constructor for states where you don't need to customize the
   // next state
   public BaseWorkerState()
   {
   }

   // Use this constructor for states where you do need to customize the 
   // next state
   public BaseWorkerState(Func<Unit, IState> createCompletedState)
   {
      this.createCompletedState = createCompletedState;
   }
}

public class BakerDeliverGrainState : BaseWorkerState, IState
{
   public BakerDeliverGrainState(Func<Unit, IState> createCompletedState) 
      : base(createCompletedState)
   {
   }

   public void Execute()
   {
      if (unit.ReachedDestination())
      {
         // Reached destination, state completed
         storage.Store(unit.TakeResource());
         unit.stateMachine.ChangeState(this.createCompletedState(unit));
       }
   }
}

然后,当您为每个单元类型创建一个状态时,您可以传入一个函数,该函数将创建适当的“完成时”状态(我猜测您的单元的架构 class)。

// When the baker is done delivering grain, he'll go into this state
public class BakerIdleState: IState
{
   public BakerIdleState(Unit unit) : base(unit)
   {
   }  
}

public class Baker : Unit
{
   public void DeliverGrain()
   {
      var newState = new BakerDeliverGrainState(unit => 
      {
         return new BakerIdleState(unit);
      }); 
      this.stateMachine.ChangeState(newState);
   }
}

当然,如果子状态 (BakerIdleState) 也需要自定义,那么您必须做同样的事情来设置该状态的下一个状态,这会变得更加复杂。