例如,拥有一个具有深层次继承层次的GameObject基类可能对维护有利。
实际上,对于可维护性而言,深层层次通常比浅层层次更差,并且游戏对象的现代建筑风格正趋向于浅层,基于聚合的方法。
但是我认为这种方法会产生性能问题。另一方面,所有游戏对象的数据和功能都可以是全局的。这将是维护上的麻烦,但可能更接近于性能最佳的游戏循环。
您显示的循环可能存在性能问题,但不存在后续语句所暗示的问题,因为您在GameObject
类中具有实例数据和成员函数。相反,问题是,如果您将游戏中的每个对象都视为完全相同,则可能不是在智能地对这些对象进行分组-它们可能会随机散布在整个列表中。然后,潜在地,对该对象的update方法的每次调用(该方法是否为全局函数,以及该对象是否具有实例数据或“全局数据”都在要索引的表中或周围浮动)都是与上一次循环迭代中的更新调用不同。
这可能会给系统带来更大的压力,因为您可能需要将具有相关功能的内存分页到内存中和从内存中调出,并更频繁地重新填充指令高速缓存,从而导致循环变慢。不管这是通过肉眼(甚至在分析器)可观察到的取决于究竟什么是认为是“游戏对象,”有多少人上平均存在,还有什么在你的应用是怎么回事。
面向组件的对象系统是当今流行的趋势,它利用聚合比继承更可取的思想。这样的系统可能允许您拆分组件的“更新”逻辑(其中“组件”被粗略地定义为某些功能单元,例如代表某些对象的物理模拟部分的事物,由物理系统处理) )连接到多个线程(按组件类型区分)(如果可能),可能会提高性能。至少您可以组织这些组件,以使给定类型的所有组件一起更新,从而最佳利用CPU的缓存。在此线程中讨论了这种面向组件的系统的示例。
这样的系统通常是高度解耦的,这也有利于维护。
面向数据的设计是一种相关的方法-它以使对象围绕对象所需的数据为首要任务,以便可以有效地批量处理数据(例如)。通常,这意味着组织将试图将用于同一目的的数据群集在一起并一次运行的组织。它从根本上与OO设计不兼容,您可以在GDSE上找到有关此问题的一些话题。
实际上,一种更好的游戏循环方法将是替代您原来的方法
foreach(GameObject g in gameObjects) g.update();
更像
ProcessUserInput();
UpdatePhysicsForAllObjects();
UpdateScriptsForAllObjects();
UpdateRenderDataForAllObjects();
RenderEverything();
在这样的世界里,每一个GameObject
可能有一个指针或引用其自身PhysicsData
或Script
或RenderData
,因为你可能需要一个单独的基础上与对象进行交互的情况,但实际PhysicsData
,Scripts
,RenderData
,等等都会被它们各自的子系统资(物理模拟器,脚本托管环境,渲染器)并如上所述进行批量处理。
这是非常重要的要注意,这种方法是不是灵丹妙药,不会总是产生的性能改善(虽然它通常是一个更好的设计比深继承树)。如果您只有很少的对象,或者您无法有效地并行化更新的对象,那么您很可能会发现基本上没有性能差异。
不幸的是,没有最佳的魔术循环-每个游戏都不相同,可能需要以不同的方式进行性能调整。因此,在盲目地接受互联网上某个随机家伙的建议之前,测量(分析)事物非常重要。