我已经有大约 10 年没有编写游戏了(我上次的经历是 DJGPP + Allegro),但我想我应该在周末检查一下 XNA,看看它是如何发展的。

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

您应该在多大程度上依赖 C# 的委托和事件来驱动游戏?作为一名应用程序程序员,我大量使用委托和事件,但我不知道这样做是否会产生很大的开销。

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

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

我使用后者,因为它允许我将事件链接在一起并很好地自动化引擎的大部分。突然间,原本庞大而复杂的事情被简化为少数 3-5 行事件处理程序……这真是太美妙了。

但是,如果每纳秒触发的事件处理程序会导致严重的速度减慢,我将删除它并采用循环方法。

有想法吗?

有帮助吗?

解决方案

如果您将事件视为订阅者列表,那么在您的代码中您所做的就是注册订阅者。在 CLR 级别实现这一点所需的指令数量可能是最少的。

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

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

写得好,我会支持活动/代表,直到我能证明这是一个问题。

您真正知道这对您来说是否是一个问题的唯一方法是分析您的代码 - 对于任何游戏开发您都应该这样做!

其他提示

重要的是要认识到 C# 中的事件不是排队的异步事件(例如 Windows 消息队列)。它们本质上是函数指针的列表。因此,引发事件并不比迭代函数指针列表并调用每个函数指针带来更糟糕的性能影响。

同时,认识到正因为如此,事件是同步的。如果您的活动 听众 太慢了,你会减慢课堂速度 提高 事件。

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

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

使用委托可能会产生隐式的、隐藏的垃圾。垃圾可能是导致性能问题的主要原因,尤其是在 XBox360 上。

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

    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 类继承并继承到 CameraController 类,并将其添加到 Game.Component 集合中。然后您可以创建相机类并将它们添加到相机控制器中。

这样做将导致相机控制器被定期调用,并且能够选择并激活正确的相机或多个相机(如果这是您想要的)。

这是一个例子(他的所有教程都很棒):重新编码

顺便说一句,您可能有兴趣知道 肖恩·哈格里夫斯, ,原开发者 快板, ,是 XNA 团队的主要开发人员之一:-)

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

假设您确实想保持追逐摄像头更新,并且它不仅仅是一个示例,那么您正在寻找的不是一个事件(尽管事件也可能起到同样的作用),如果您正在关注一个化身,那么它可能会是大部分时间都在移动。

我发现非常有效的一种方法是使用分层转换,如果您有效地实现这一点,相机将不会是从这样的系统中受益的唯一对象,目标是将相机保持在其所在对象的坐标空间内追踪。

如果您想对相机跟踪对象的速度和方式应用一些弹性,那么这种方法并不是最好的方法,为此,最好使用更新调用、参考以及一些基本的加速和阻力物理原理。

事件对于那些偶尔发生的事情或者影响应用程序许多不同方面的事情更有用,比如一个角色死亡,可能许多不同的系统想要知道这样的事件,杀死统计数据,控制人工智能,以及依此类推,在这种情况下,跟踪所有必须不断检查是否发生这种情况的对象远不如抛出事件并仅在事件发生时通知所有感兴趣的对象有效。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top