【问题标题】:Game Programming and Event Handlers游戏编程和事件处理程序
【发布时间】:2008-09-15 15:30:25
【问题描述】:

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

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

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

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

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

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

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

想法?

【问题讨论】:

    标签: c# xna camera


    【解决方案1】:

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

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

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

    写得很好,在我能证明这是一个问题之前,我会支持活动/代表。

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

    【讨论】:

      【解决方案2】:

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

      同时,意识到正因为如此,事件是同步的。如果你的事件 listener 很慢,你会减慢类引发事件。

      【讨论】:

        【解决方案3】:

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

        与常规函数调用相比,事件的开销很小。

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

        以下代码以 EntityVisitor 对象的形式每秒生成大约 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)
            {
            }
        

        只要避免产生垃圾,委托就足以满足大多数目的。由于存在隐患,我更喜欢避开它们,使用接口代替。

        【讨论】:

          【解决方案4】:

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

          恕我直言(或者如果你问我的同事,也不是那么谦虚)是事件句柄的开销将被游戏中的其他元素(如渲染)压倒。鉴于在正常的 .Net 编程中大量使用事件,我认为底层代码已经得到很好的优化。

          说实话,我认为使用 UpdateCameras 方法可能是过早的优化。事件系统可能除了相机还有更多用途。

          【讨论】:

            【解决方案5】:

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

            答案是“只要你觉得舒服就行”。

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

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

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

            【讨论】:

              【解决方案6】:

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

              【讨论】:

              • 我确实注意到了。这是一个小小的世界。
              【解决方案7】:

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

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

              我发现一种非常有效的方法是使用分层转换,如果您有效地实现这一点,相机将不会是唯一受益于这种系统的对象,目标是将相机保持在它正在跟踪的对象。

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

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

              【讨论】:

                猜你喜欢
                • 2020-01-04
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-01-25
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多