如何编写一个状态机,这样我就不必使用 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
) 也需要自定义,那么您必须做同样的事情来设置该状态的下一个状态,这会变得更加复杂。
我正在制作一个城市管理游戏,其中的工人完全由状态机控制。我有一个“问题”,我发现自己重写了很多 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
) 也需要自定义,那么您必须做同样的事情来设置该状态的下一个状态,这会变得更加复杂。