游戏编程和事件处理程序

我没有编写游戏大约10年(我的最后一次经历是DJGPP + Allegro),但我想我会在周末看看XNA,看看它是如何形成的。

我印象非常深刻,但是当我继续拼凑游戏引擎时,我有一个(可能)基本问题。

您应该依靠C#的代表和活动来推动游戏多少? 作为应用程序程序员,我大量使用委托和事件,但我不知道这样做是否有很大的开销。

在我的游戏引擎中,我设计了一种“追逐凸轮”,它可以附加到一个物体上,然后重新计算它相对于物体的位置。 当对象移动时,有两种方法可以更新追逐凸轮。

  • 在主游戏循环中有一个“UpdateCameras()”方法。
  • 使用事件处理程序,并使chase cam订阅object.OnMoved。

我正在使用后者,因为它允许我将事件链接在一起并很好地自动化引擎的大部分。 突然之间,巨大而复杂的东西会落到少数3-5线事件处理程序中……这是一种美。

但是,如果每纳秒触发的事件处理程序变成一个主要的减速,我将删除它并采用循环方法。

想法?

如果您将某个事件视为订阅者列表,则在您的代码中,您所做的只是注册订阅者。 在CLR级别,实现这一目标所需的指令数量可能很少。

如果您希望您的代码是通用的或动态的,那么您需要在调用事件之前检查是否订阅了某些内容。 C#和.NET的事件/委托机制以极低的成本(就CPU而言)为您提供。

如果您真的关心每个时钟周期,那么您永远不会编写通用/动态游戏逻辑。 这是可维护/可配置代码与直接速度之间的权衡。

写得好,我赞成事件/代表,直到我能certificate这是一个问题。

你真正知道它是否是一个问题的唯一方法是分析你的代码 – 你应该为任何游戏开发做任何事情!

重要的是要意识到C#中的事件不是排队的异步事件(例如,Windows消息队列)。 它们本质上是一个函数指针列表。 因此,通过迭代函数指针列表并调用每个函数指针,提升事件的性能影响不会更大。

同时,意识到因此,事件是同步的。 如果您的事件监听器很慢,那么您将放慢提升事件的速度。

这里的主要问题似乎是:“使用C#代理和事件的开销是多少?”

与常规函数调用相比,事件几乎没有显着的开销。

Delegates的使用可以创建隐含的,因此隐藏的垃圾。 垃圾可能是导致性能问题的主要原因,特别是在XBox360上。

以下代码以EntityVisitor对象的forms每秒生成大约2000字节的垃圾(60 fps):

private delegate void SpacialItemVisitor(ISpacialItem item); protected override void Update(GameTime gameTime) { m_quadTree.Visit(ref explosionCircle, ApplyExplosionEffects); } private void ApplyExplosionEffects(ISpacialItem item) { } 

只要你避免产生垃圾,代表就足够快,可以用于大多数目的。 由于隐藏的危险,我宁愿避免使用它们而是使用接口。

在我离开实际工作的额外时间里,我也在学习XNA。

恕我直言(或者如果你问我的同事那么谦虚)是事件句柄的开销将被游戏中的其他元素所淹没,例如渲染。 鉴于在正常的.Net编程中大量使用事件,我将对底层代码进行很好的优化。

说实话,我认为使用UpdateCameras方法可能是一个不成熟的优化。 事件系统可能具有除相机之外的更多用途。

XNA鼓励使用接口,事件和委托来驱动用它编写的东西。 看一下为您设置的GameComponent相关类。

答案是,“就像你感到舒服”。

稍微详细说明一下,例如,您从gamecomponent类获取并inheritance到cameracontroller类并将其添加到Game.Component集合中。 然后,您可以创建相机类并将它们添加到相机控制器。

执行此操作将导致定期调用摄像头控制器,并且能够选择并激活正确的摄像头或多个摄像头(如果这是您的目的)。

这是一个例子(他的所有教程都很棒): ReoCode

顺便说一下,您可能有兴趣知道Allegro的原始开发人员Shawn Hargreaves是XNA团队的主要开发人员之一:-)

在进入事件对性能的影响之前,您必须首先评估是否需要它。

假设你真的试图让追逐凸轮更新并且它不仅仅是一个例子,你所寻找的不是一个事件(虽然事件也可以做到这一点),如果你追随一个化身的可能性是它将是大部分时间都在移动。

我发现一种非常有效的方法是使用分层变换,如果你有效地实现这一点,摄像机将不是唯一受益于这种系统的对象,目标是将摄像机保持在对象的坐标空间内。跟踪。

如果你想对摄像机跟踪物体的速度和方式施加一些弹性,那么这种方法并不是最好的方法,因此,最好使用更新调用,参考和一些基本的加速度和阻力物理。

事件对于仅偶尔发生或影响应用程序的许多不同方面的事物更有用,例如角色死亡,可能许多不同的系统想要知道这样的事件,杀死统计数据,控制AI和等等,在这种情况下,跟踪所有必须经常检查是否发生这种情况的对象远比投掷事件并且仅在发生事件时通知所有感兴趣的对象有效。