【问题标题】:How to organize entities in an ECS model?如何在 ECS 模型中组织实体?
【发布时间】:2020-05-19 17:01:08
【问题描述】:

我有一个渲染系统,它遍历所有 MeshDrawData 组件并批量绘制它们。我的 ECS 实现只允许每个实体使用一种类型的组件。

现在我想代表“玩家”乒乓球拍。我的 OOP 心态是这样说的:

Pseudocode:
auto e = createEntity();
createSpriteComponent(e,...); // this creates a MeshDrawData internally for e entity.
createColliderComponent(e,...);

这没问题,但是假设现在我也想渲染一条线。 如果我这样做:

Pseudocode:
auto e = createEntity();
createSpriteComponent(e,...); // this creates a MeshDrawData internally for the e entity.
createColliderComponent(e,...);
createLineComponent(e,...); // this creates a MeshDrawData internally for the e entity

这里可以看出问题了。我为实体e创建了两个MeshDrawData组件。。

鉴于我的虚幻引擎背景,我创建了一个演员并向其添加组件。我一直认为在 ECS 中,实体类似于演员,但我发现我完全错了。

您如何组织您的实体,例如允许使用我之前提到的用例?一个实体应该代表什么?

可能的解决方案:

  1. 永远不要使用在同一实体中创建相同 MeshDrawData 的 SpriteComponent 和 LineComponent 创建实体..(显而易见但容易出错)
  2. 为每个 SpriteComponent 和/或 LineComponent 创建一个子实体,并将它们添加到各自的子实体。这会起作用,但它会使实体层次结构树变长..不确定它是否更容易出错。 ...

【问题讨论】:

    标签: c++ entity game-engine entity-component-system


    【解决方案1】:

    1:1 Entity:Component 是一个无聊的限制,也是大多数ECS引擎的一个很好的限制。

    要解决这些问题,我通常会执行以下操作之一:-

    1. 默认禁止 :: 游戏引擎将在您的第二种情况下抛出 assert-fail。

    2. 添加检查 例如在createLineComponent MeshDrawData 是否已经存在,并做一些自定义的事情。

      我主要是这样做的:-

      void createLineComponent(Entity e){
          auto meshComponent=engine->addJustInCase<MeshDrawData>(e);
          //^ if the component exists - just request the component, if not, create it
          meshComponent->setFormat ...
      }
      
    3. 拆分实体添加一对多关系 :: 适用于过于复杂的实体。

      3.1 保持简单 - 父缓存子实体作为其字段。

      3.2 完整系统,用于某个 1:N 关系。
      子关系系统的类型应该非常具体
      例如1:N Collider-Sprite,不是1:N entity-entity

    在我的游戏中,我将它们混合在大约 60:30:10(9:1) 左右。它运作良好。
    如果它开始变得一团糟——使用工厂模式来封装它。

    如果有人有任何(更好的)想法,请回答。我也想听。

    【讨论】:

    • 感谢您的回答。现在我正在做你的2)方法。我用添加的需要它的最新组件覆盖 MeshDrawData。我不会选择这个作为正确答案,看看有没有人有别的想法。
    • @FrameBuffer 不错。如果你发现任何有用的东西或用这种方法完成你的游戏,请告诉我。 :)
    • 我想了更多,我的结论是你可以决定把你所有的状态放在 ecs 中或与系统共享。我现在的方法是将所有状态放入组件中,以保持一致。鉴于我决定为实体拥有的每个不同的“渲染器组件”创建一个子组件。并在实体的“渲染器组件”中保存对该实体的引用,以防您必须访问它。
    • @FrameBuffer 只是为了检查我的理解。您是否... (1) 通过增强您的 ECS 核心引擎,允许 1 个实体拥有 > 1 个 renderer component?或者 (2) 减少/减少 renderer component 不再是 ECS 组件,而是手动管理它?或者是其他东西? ...我只做了(2)一次。它位于我的物理引擎 (manifold component) 的性能关键区域。
    • 我有“实体中每种类型只有一个组件”。从架构的角度来看,我改变的是具有 LineRenderer 和 SpriteRenderer 的实体对我来说没有意义,所以我结束了你的第一个 (1) 方法(因为它有问题)。例如,Sprite 是具有 Transform 和 Sprite(将创建和处理自己的 MeshDrawData)的实体。因此,具有精灵的角色将由具有子实体(精灵)的实体(玩家)表示。如果玩家要画一条线,线是另一个实体(变换,LineRenderer->MeshDrawData)
    猜你喜欢
    • 1970-01-01
    • 2014-04-21
    • 1970-01-01
    • 2011-10-09
    • 2021-09-29
    • 2019-11-12
    • 2014-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多