【问题标题】:How to write a state machine so that I don't have to duplicate states with 99% similar code?如何编写状态机,这样我就不必使用 99% 相似的代码来复制状态?
【发布时间】:2021-03-27 16:06:19
【问题描述】:

我正在制作一个城市管理游戏,其中的工作人员完全由状态机控制。我有一个“问题”,我发现自己重写了很多 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()
    {
        
    }
}

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

【问题讨论】:

    标签: c# unity3d logic state-machine


    【解决方案1】:

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

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

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

    // 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) 也需要自定义,那么您必须做同样的事情来设置该状态的下一个状态,这会变得更加复杂。

    【讨论】:

    • 真的很有趣,明天我会尝试一下,可以工作! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-08
    • 1970-01-01
    • 2021-01-10
    • 2023-03-30
    • 2012-10-16
    • 2013-01-18
    相关资源
    最近更新 更多