二维侧滚动的“最佳”游戏循环


14

是否可以为2D侧滚动游戏循环描述“最佳”(就性能而言)布局?在这种情况下,“游戏循环”接受用户输入,更新游戏对象的状态并绘制游戏对象。

例如,拥有一个具有深层次继承层次的GameObject基类可能对维护很有帮助...您可以执行以下操作:

foreach(GameObject g in gameObjects) g.update();

但是我认为这种方法会产生性能问题。

另一方面,所有游戏对象的数据和功能都可以是全局的。这将是维护上的麻烦,但可能更接近于性能最佳的游戏循环。

有什么想法吗? 我对接近最佳游戏循环结构的实际应用感兴趣...即使我为了获得出色的性能而为维护感到头疼。


Answers:


45

例如,拥有一个具有深层次继承层次的GameObject基类可能对维护有利。

实际上,对于可维护性而言,深层层次通常比浅层层次更差,并且游戏对象的现代建筑风格正趋向于浅层,基于聚合的方法

但是我认为这种方法会产生性能问题。另一方面,所有游戏对象的数据和功能都可以是全局的。这将是维护上的麻烦,但可能更接近于性能最佳的游戏循环。

您显示的循环可能存在性能问题,但不存在后续语句所暗示的问题,因为您在GameObject类中具有实例数据和成员函数。相反,问题是,如果您将游戏中的每个对象都视为完全相同,则可能不是在智能地对这些对象进行分组-它们可能会随机散布在整个列表中。然后,潜在地,对该对象的update方法的每次调用(该方法是否为全局函数,以及该对象是否具有实例数据或“全局数据”都在要索引的表中或周围浮动)都是与上一次循环迭代中的更新调用不同。

这可能会给系统带来更大的压力,因为您可能需要将具有相关功能的内存分页到内存中和从内存中调出,并更频繁地重新填充指令高速缓存,从而导致循环变慢。不管这是通过肉眼(甚至在分析器)可观察到的取决于究竟什么是认为是“游戏对象,”有多少人上平均存在,还有什么在你的应用是怎么回事。

面向组件的对象系统是当今流行的趋势,它利用聚合比继承更可取的思想。这样的系统可能允许您拆分组件的“更新”逻辑(其中“组件”被粗略地定义为某些功能单元,例如代表某些对象的物理模拟部分的事物,由物理系统处理) )连接到多个线程(按组件类型区分)(如果可能),可能会提高性能。至少您可以组织这些组件,以使给定类型的所有组件一起更新,从而最佳利用CPU的缓存。在此线程中讨论了这种面向组件的系统的示例。

这样的系统通常是高度解耦的,这也有利于维护。

面向数据的设计是一种相关的方法-它以使对象围绕对象所需的数据为首要任务,以便可以有效地批量处理数据(例如)。通常,这意味着组织将试图将用于同一目的的数据群集在一起并一次运行的组织。它从根本上与OO设计不兼容,您可以在GDSE上找到有关此问题的一些话题。

实际上,一种更好的游戏循环方法将是替代您原来的方法

foreach(GameObject g in gameObjects) g.update();

更像

ProcessUserInput();
UpdatePhysicsForAllObjects();
UpdateScriptsForAllObjects();
UpdateRenderDataForAllObjects();
RenderEverything();

在这样的世界里,每一个GameObject可能有一个指针或引用其自身PhysicsDataScriptRenderData,因为你可能需要一个单独的基础上与对象进行交互的情况,但实际PhysicsDataScriptsRenderData,等等都会被它们各自的子系统资(物理模拟器,脚本托管环境,渲染器)并如上所述进行批量处理。

这是非常重要的要注意,这种方法是不是灵丹妙药,不会总是产生的性能改善(虽然它通常是一个更好的设计比深继承树)。如果您只有很少的对象,或者您无法有效地并行化更新的对象,那么您很可能会发现基本上没有性能差异。

不幸的是,没有最佳的魔术循环-每个游戏都不相同,可能需要以不同的方式进行性能调整。因此,在盲目地接受互联网上某个随机家伙的建议之前,测量(分析)事物非常重要。


5
上帝,这是一个很好的答案。
Raveline

2

游戏对象编程风格适合较小的项目。随着项目变得非常庞大,您将最终获得深层次的继承层次,而游戏对象库将变得非常繁重!

举个例子...假设您开始创建具有最小属性的游戏对象库,这些属性包括:Position(用于x和y),displayObject(这是指图像,如果它是绘图元素),宽度,高度等。

现在稍后,如果我们需要添加一个具有动画状态的子类,那么您可能会将“动画控制代码”(例如currentAnimationId,此动画的帧数等)移至GameObjectBase,以为这些对象将具有动画。
稍后,如果要添加静态的刚体(没有任何动画),则需要在GameObject Base的更新功能中检查“动画控制代码”(尽管要检查是否存在动画)。 ..这很重要!)与此相反,如果您遵循基于组件的结构,则将在对象上附加一个``动画控制组件''。如果需要它,则将其附加;对于静态物体,您将不会附加该组件。这样,就可以避免不必要的检查。

因此,选择样式的选择取决于项目的大小.GameObject结构仅对于较小的项目很容易掌握,希望这会有所帮助。


@Josh Petrie-真的是一个很好的答案!
2011年

@Josh Petrie-确实是一个有用链接的很好答案!(很抱歉,您不知道如何在您的帖子旁边放置此评论:P)
Ayyappa

通常,您可以单击我的答案下方的“添加评论”链接,但这需要比您当前更高的声誉(请参阅gamedev.stackexchange.com/privileges/comment)。谢谢!
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.