我正在为视频游戏中的游戏对象开发状态机。我希望这种状态机易于使用;为了调用状态更改,应在状态机上调用“提高”方法。我当前的设计涉及使用通用类型作为事件标识符:

stateMachine.Raise<Event>();


具有以下定义:

public void Raise<EventType>() where EventType : Event


然后,状态机找到处理此事件类型的状态,并根据它们提供的转换来更新状态。我最初考虑使用字符串来识别事件类型,例如:

stateMachine.Raise("Event");


或和枚举:

stateMachine.Raise(GameObject.Event);


但是我觉得这两种方法都存在问题。字符串是两个灵活的字符串,在编译时不能进行错误检查以确保它们有效。枚举不能扩展,限制事件对扩展GameObject的每个类的可用性,使事件调用不必要地延长,并导致状态机内部类型检查出现问题。但是,使用类作为标识的方法意味着我在GameObject内部声明了事件,如下所示:

protected class SomeEvent : Event {}
protected class OtherEvent : Event {}
...
protected class AnotherEvent : Event {}


尽管很优雅,但我觉得这在某种程度上会变成代码的味道或可怕的做法,给人的印象是我滥用类的目的。最终,我将有数百个空类乱扔我的代码库,我认为这是一个潜在的问题。真正的最佳选择是什么?

最佳答案

由于您是为视频游戏而写的,并且除非这是游戏的功能,否则您的事件和状态应在规范中定义,因此一旦定义,可能发生的事件的清单就不会多动。因此,选择来自共同祖先的课程。

为什么不枚举或字符串?因为枚举和字符串不携带数据。通常,您需要与事件相关的一些数据,因为它将使您可以按家庭对事件进行分组。您不需要GrumpinessIncreaseEventJoyIncreaseEvent,而是需要其中包含一些信息的MoodChangeEvent(哪种类型的情绪会受到影响,受到多少影响,等等)。

此外,您还可以将一些事件松散地键入,以防您稍后可能遇到的未知未知事件(例如,一个具有object属性的事件,然后在运行时将其转换为某种类型)



回复:OP的评论:我确实认为您应该使用实例而不是类型。您不会通过PunchInFace,而是通过new DamageEvent() {type = Damage.PUNCH, source= PuncherGuy.Fist, Target=PunchedGuy.Face},因为这种事件对游戏中的许多组件(物理引擎,得分引擎等)更友好。

再次取决于游戏的完成方式(这使我认为实际上应该关闭该问题,因为它是基于Opinon的),但是当您按类型引发PunchInFaceEvent时,您能说什么呢?谁打谁?哪里?什么时候?等等...

09-04 06:00
查看更多