Nomad游戏引擎:第4.2部分-添加手柄

掌握组件

这篇文章是系列文章的一部分,我在其中记录我从头开始构建ECS游戏引擎的经验。 请查看 该项目 主页,以 获取更多帖子,信息和源代码。

由于实体组件系统是如何设计的,因此在引用ECS中的实体和组件时,尤其是涉及所有权时,实际上有很多经典的推论。 传统上,组件是由实体拥有的。 假设我的玩家穿着防具(ArmorComponent)。 我们认为所有权的方式是玩家“拥有”装甲。 因此,如果我们尝试为玩家提供装甲,我们希望代码看起来像这样:

  player.equip(装甲) 

或翻译成我们的ECS,

  playerEntity.addComponent(armorComponent) 

但是,由于我们知道架构在后台的工作方式,所以我们知道组件实际上是由其组件管理器拥有的-他们是“拥有自己的”。 实际上,这意味着我们的代码看起来像这样:

  armourComponentManager.addComponent(playerEntity,ArmorComponent); 

或者,更现实,但也更尴尬,

  world.getComponentManager () 
.addComponent(playerEntity,ArmorComponent);

该代码本质上与我们所说的“逻辑”所有权相反。

尽管我们可以尝试使我们游戏引擎的所有用户都学习这种新的(违反直觉的)所有权概念,但实际上并没有太大意义。 实体组件系统已经很难推理了,因为它们是一种新的范例,它消除了典型的面向对象方法—为什么仅通过后端的实现方式通过强制执行向后逻辑使其变得更加复杂?

更有意义的是:

  armourComponentManager.addComponent(playerEntity,ArmorComponent); 
healthComponentManager.addComponent(playerEntity,healthComponent);
motionComponentManager.addComponent(playerEntity,motionComponent);

或这个:

  playerEntity.addComponent(armorComponent); 
playerEntity.addComponent(healthComponent);
playerEntity.addComponent(motionComponent);

显然,第二个更有意义,因为它代表了我们实际上对实体的看法。 那么,如何在不更改组件管理器基础结构的情况下尽可能接近第二种语法呢?

实体句柄

我们将制作一个“句柄”,它包装了暴露诸如EntityHandle.addComponent()之类的方法所需的所有信息。 这里要注意的问题是,如果我们的实体改变世界,我们将遇到一些问题,因为我们的EntityHandle不会自动正确地自我更新。 这是我们以后必须跨越的一座桥梁,但是现在我们只与一个世界一起工作,因此我们可以假设EntityHandle在删除实体之前将保持有效。 这是我们需要存储在EntityHandle中的数据:

  EntityHandle { 
实体实体;
世界*世界;
}

请注意,我们的EntityHandle仍然轻巧。 现在,我们只需要添加我们的辅助方法:

因此,通过添加句柄,我们基本上免费地获得了许多易于阅读和编写的代码。