我没有编写游戏大约10年(我的最后一次经历是DJGPP + Allegro),但我想我会在周末看看XNA,看看它是如何形成的。
我印象非常深刻,但是当我继续拼凑游戏引擎时,我有一个(可能)基本问题。
你应该依靠C#的代表和活动来推动游戏?作为一名应用程序员,我大量使用委托和事件,但我不知道这样做是否有很大的开销。
在我的游戏引擎中,我设计了一种“追逐凸轮”,它可以附加到一个物体上,然后重新计算它相对于物体的位置。当对象移动时,有两种方法可以更新追逐凸轮。
我正在使用后者,因为它允许我将事件链接在一起并很好地自动化引擎的大部分内容。突然之间,巨大而复杂的东西会落到少数3-5线事件处理程序中......它很美。
然而,如果事件处理程序每纳秒触发一次变成一个主要的减速,我将删除它并采用循环方法。
想法?
答案 0 :(得分:10)
如果您将某个事件视为订阅者列表,则在您的代码中,您所做的只是注册订阅者。在CLR级别,实现这一目标所需的指令数量可能很少。
如果您希望您的代码是通用的或动态的,那么您需要在调用事件之前检查是否订阅了某些内容。 C#和.NET的事件/委托机制以极低的成本(就CPU而言)为您提供。
如果您真的关心每个时钟周期,那么您永远不会编写通用/动态游戏逻辑。这是可维护/可配置代码与直接速度之间的权衡。
写得好,我赞成事件/代表,直到我能证明这是一个问题。
你真正知道这对你来说是一个问题的唯一方法就是分析你的代码 - 你应该为任何游戏开发做任何事情!
答案 1 :(得分:4)
重要的是要意识到C#中的事件不是排队的异步事件(例如Windows消息队列)。它们本质上是一个函数指针列表。因此,通过迭代函数指针列表并调用每个事件,提升事件的性能影响不会更差。
同时,意识到因此,事件是同步的。如果您的事件侦听器很慢,那么您将放慢提升事件的速度。
答案 2 :(得分:2)
这里的主要问题似乎是: “与使用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)
{
}
只要您避免生成垃圾,代表就可以在大多数情况下使用。由于存在隐患,我宁愿避免使用它们而是使用接口。
答案 3 :(得分:1)
XNA鼓励使用接口,事件和委托来驱动用它编写的东西。看一下为你设置的GameComponent相关类。
答案是,“尽可能让你感到舒服”。
详细说明一下,例如,您将gamecomponent类中的一个继承并继承到cameracontroller类并将其添加到Game.Component集合中。然后,您可以创建相机类并将它们添加到相机控制器。
执行此操作将导致定期调用摄像头控制器,并且能够选择并激活正确的摄像头或多个摄像头(如果这是您的目的)。
这是一个例子(他的所有教程都很棒): ReoCode
答案 4 :(得分:1)
在我离开实际工作的额外时间里,我也一直在学习XNA。
恕我直言(或者如果你问我的同事那么谦虚)是事件处理的开销会被游戏中的其他元素所淹没,例如渲染。鉴于在正常的.Net编程中大量使用事件,我将对底层代码进行很好的优化。
老实说,我认为使用UpdateCameras方法可能是一个不成熟的优化。事件系统可能有更多的用途,而不是相机。
答案 5 :(得分:1)
顺便说一下,您可能有兴趣知道Shawn Hargreaves,Allegro的原始开发人员,是XNA团队的主要开发人员之一: - )
答案 6 :(得分:1)
在进入事件对绩效的影响之前,您必须首先评估是否需要它。
假设你真的想要更新追逐摄像头并且它不仅仅是一个例子,你正在寻找的不是一个事件(虽然事件也可以做到这一点),如果你追随一个化身可能性是它大部分时间都会移动。
我发现一种非常有效的方法是使用分层变换,如果你有效地实现这一点,摄像机将不是唯一受益于这种系统的对象,目标是将摄像机保持在坐标空间内。对象是跟踪。
如果您希望对摄像机跟踪物体的速度和方式应用一些弹性,那么这种方法并不是最好的方法,因此,最好使用更新调用,参考和一些基本的加速度,阻力物理学。
事件对于只会不时发生或影响应用程序的许多不同方面的事情更有用,例如角色死亡,可能许多不同的系统都想知道这样的事件,杀死统计数据,控制AI,等等,在这种情况下,跟踪所有必须不断检查是否发生这种情况的对象远比投掷事件并且仅在发生事件时通知所有感兴趣的对象有效。< / p>