英文原文: https://github.com/mzaks/EntitasCookBook
当我们想要获取所有具有位置组件的实体时,我们创建一个组并对其进行迭代。但是,如果我们希望在某个位置获取实体,那又如何呢?我们可以遍历所有具有位置的实体并仅收集具有所需位置的实体。或者我们可以使用索引。
为了创建索引,我们必须将组件值注释如下:
using Entitas;
using Entitas.CodeGeneration.Attributes;
[Game]
public sealed class PositionComponent : IComponent {
[EntityIndex]
public IntVector2 value;
}
EntityIndex 注释将告诉代码生成器在上下文中创建 API,以便用户能够通过给定的 IntVector2 值获取实体。
以下是 MatchOne 中 ProcessInputSystem 的片段:
foreach (var e in _contexts.game.GetEntitiesWithPosition(
new IntVector2(input.x, input.y)
).Where(e => e.isInteractive)) {
e.isDestroyed = true;
}
在这个片段中,我们要求上下文为我们提供位置上的所有实体,其中“输入”受到影响,我们过滤掉非交互的实体。
在内部,索引是一个组观察者。它是在上下文初始化时创建的,从一开始就订阅组事件。当我们开始创建实体并向它们添加组件时,它们将开始进入组,并且索引将被通知添加了具有以下组件的实体。我们可以使用组件的值作为 HashMap 中的键,其中值是实体本身。这样我们就建立了一个索引。当我们更换或移除组件时。该索引也由该组通知。它获取前一个组件,因此它可以从 HashMap 中删除条目,如果我们用另一个组件替换它,它将再次接收带有新值的添加事件。
在 Entitas-CSharp 中,我们有两种类型的内置索引。 EntityIndex 和 PrimaryEntityIndex。 EntityIndex 由 HashMap 支持,该 HashMap 将一组实体存储为值。含义 - 您可以在同一位置有多个实体。 PrimaryEntityIndex 确保每个键只与一个实体相关联。如果您有一个 Id 组件并且您想通过此 Id 查找实体,这非常好。这也是我们推荐的,当您需要存储从一个实体到另一个实体的引用时(更多内容请参见 ingredience 章节)。
如上一段所述,Entitas-CSharp 仅实现了两种简单的实体索引策略。你可能需要一个更复杂的,你想在一个范围内获取实体,或者有一个更复杂的索引键。在这种情况下,请查看 AbstractEntityIndex 类。有了本书提供的知识,理解实现和编写自己的自定义索引应该相当容易。