游戏循环性能和组件方法

时间:2010-04-20 21:54:25

标签: performance architecture components game-loop

我有一个组织游戏循环的想法。我对性能有些怀疑。可能有更好的做事方式。

考虑一下你有一系列游戏组件。他们都被要求在每次游戏循环迭代中做一些事情。例如:

GameData data; // shared
app.registerComponent("AI", ComponentAI(data) );
app.registerComponent("Logic", ComponentGameLogic(data) );
app.registerComponent("2d", Component2d(data) );
app.registerComponent("Menu", ComponentMenu(data) )->setActive(false);
//...
while (ok)
{
//...
app.runAllComponents();
//...
}

优点:

  1. 良好的基于​​组件的应用程序,无依赖性,良好的模块化
  2. 我们可以激活/停用,动态注册/取消注册组件
  3. 可以透明地删除或替换某些组件,系统仍然可以正常工作(将2d更改为3d)(团队合作:每个程序员创建他/她自己的组件,并且不需要其他组件来编译代码)
  4. 疑惑:

    1. 游戏循环中的内部循环,虚拟调用Component :: run()
    2. 我希望Component :: run()返回bool值并检查此值。如果返回false,则必须停用组件。因此内循环变得更加昂贵。
    3. 嗯,这个解决方案有多好?你是否在实际项目中使用过它?

4 个答案:

答案 0 :(得分:5)

一些C ++程序员对虚拟函数的开销有太多担忧。与函数无关,虚拟调用的开销通常可以忽略不计。布尔检查也不是很贵。

在最易于维护的代码中执行任何操作。仅在您需要时才进行优化。如果您确实发现需要优化,那么消除虚拟呼叫可能不是您需要的优化。

答案 1 :(得分:4)

在大多数“真实”游戏中,对组件之间的相互依赖性有非常严格的要求,并且排序很重要。

这可能会影响您,也可能不会影响您,但根据您的情况等,让物理在用户交互过程之前(或之后)生效通常很重要。在这种情况下,您可能需要一些额外的处理才能正确排序

此外,由于您最有可能会使用某种形式的场景图或空间分区,因此您需要确保您的“组件”也可以利用它。这可能意味着,根据您当前的描述,您将在树上走太多次。但是,这可以通过设计决策来解决。话虽这么说,一些组件可能只对空间分区的某些部分感兴趣,同样,你想要进行适当的设计。

答案 2 :(得分:1)

我在模块化合成音频文件生成器中使用了类似的方法。

我似乎记得在编程100个不同模块后注意到,在编写新模块时会对性能产生影响。

总的来说,我觉得这是一个很好的方法。

答案 3 :(得分:1)

也许我是oldschool,但我真的没有看到通用组件的价值,因为我没有看到它们在运行时被换掉。

struct GameObject
{
   Ai* ai;
   Transform* transform;
   Renderable* renderable;
   Collision* collision;
   Health* health;
};

这适用于从玩家到敌人到天空盒和触发器的所有内容;只需将给定对象中不需要的“组件”留空即可。您想将所有AI放入列表中吗?然后在施工时这样做。使用多态性,您可以在其中屏蔽各种不同的行为(例如,播放器的“AI”正在转换控制器输入),除此之外,不需要为所有内容使用通用基类。无论如何它会做什么?

你的“更新所有内容”必须明确地调出每个列表,但这不会改变你必须做的输入量,它只是移动它。您无需模糊地设置需要全局操作的集合集,而是明确枚举操作完成时需要操作的集合。

恕我直言,并非虚拟通话速度慢。这是游戏实体的“组件”不是同质的。他们都做了截然不同的事情,因此以不同方式对待他们是有道理的。实际上,它们之间没有重叠,所以我再次问,如果你不能以任何有意义的方式使用指向该基类的指针而不将其转换为其他类,那么基类有什么意义呢?