【问题标题】:Using class as event identifiers使用类作为事件标识符
【发布时间】:2014-10-24 08:41:41
【问题描述】:

我正在为视频游戏中的游戏对象开发状态机实现。我希望这个状态机易于使用;为了调用状态变化,应该在状态机上调用“Raise”方法。我当前的设计涉及使用泛型类型作为事件标识符:

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 {}

尽管很优雅,但我觉得在某些时候这会变成一种代码味道或糟糕的做法,我觉得我在滥用类的目的。最终,我的代码库中会出现数百个空类,我认为这是一个潜在的问题。真正的最佳选择是什么?

【问题讨论】:

  • 你说枚举是一个限制,因为它不能被扩展。但是你为什么要扩展事件的信号呢?它只是状态机改变的触发器。您希望这些事件不仅仅是未来的信号吗?
  • 事件聚合器模式通常使用类似的东西。通常你会有一些附加到事件的信息,但有时没有。当您想收到某事的通知但可能没有可以订阅的固定发布者时,它很有用。
  • @YuvalItzchakov 我不认为每个事件都会扩展很多,但这确实意味着每个新事件类都必须扩展 Event,因为 Raise 方法会检查这一点。它还可以允许特定类型的状态机,例如: HierarchicalStateMachine 它期望 HierarchicalEvent 的 Raise 方法可以不同地使用。
  • @mikez 我目前不确定信息。目前在该系统中使用事件只是为了在离散状态之间进行更改,例如;门已打开,事件“关闭”已引发,门现在已关闭。也许我想错了?
  • @sydan 假设您将拥有多个 Door 对象,您需要确定要更改哪个特定 Door 的状态。我认为你遇到的问题首先是有太多的事件,而提议的方案都没有解决这个问题。当事件种类太多时,系统将难以理解。

标签: c# class enums identifier state-machine


【解决方案1】:

由于您正在为电子游戏写作 - 除非这是游戏的一项功能 - 您的事件和状态应该在您的规范中定义,因此一旦定义,可能的事件列表不应该发生很大变化;所以选择从共同祖先派生的类。

为什么不使用枚举或字符串?因为枚举和字符串不携带数据。您通常希望将一些数据与您的活动一起使用,因为它可以让您按家庭对活动进行分组。您不需要GrumpinessIncreaseEventJoyIncreaseEvent,而是需要包含一些信息的MoodChangeEvent(影响什么类型的情绪,影响程度等)

此外,您还可以有一些松散类型的事件,以便您以后可能遇到的潜在已知未知数(例如,具有对象属性的事件,然后在运行时转换为某种类型)


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

这又一次取决于游戏是如何完成的(这让我认为这个问题实际上应该被关闭,因为它是基于意见的)但是当你按类型提出 PunchInFaceEvent 时,你能说什么?谁打了谁?在哪里?什么时候?等等……

【讨论】:

  • 您是否建议我应该更改实现以使用实际对象而不是类类型?例如:Raise(Event event) 与我目前的方法相反?我的实现可能太复杂了,GameObjects 之间还有另一个更高级别的交互使用消息,例如一个对象可能会向另一个对象发送消息“PunchInFace”。如果其他对象接收到该类型的消息,它将处理它并将某些事件传递到状态机,例如:'Hurt'。状态机本身决定这是否会导致从 Happy 到 Grumpy 以及可能从 Health 到 Injured 的转换。
  • 回答您的编辑:我看到了这样做的优点,我认为我需要离开并巩固我对将要发生哪些事件和消息以及系统的哪些部分将处理哪些部分的想法他们暴露的一些信息。
猜你喜欢
  • 2013-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多