Description
What problem does this solve or what need does it fill?
In non-trivial games, entities commonly need to be bundled together to share common behavior, despite being mostly heterogenous. As a few concrete examples:
- character models with multiple moving parts
- visual effects associated with sprites
- UI widgets composed with multiple parts, each of which has its own transform, style, sprite etc
Possible Solutions
- Allowing multiple copies of each component per entity (like nodes in Godot) is a Pandora's box of special-casing and is likely to do horrible things to our storages and conceptual clarity.
- Using a parent-child-like hierarchy tree and traversing it to apply behavior. This results in a lot of wasted recomputation.
- Storing a "WidgetID" component (or analogous) on each entity, then coordinating their behavior by looking it up within each relevant system.
- Adding a unique marker component for each entity in the entity group, then querying for it. We generally can't define these at run time, since the number of entity groups is unknown, so
min const generics might work well herewe need dynamic components (see Dynamic Systems and Components #623) (thanks @BoxyUwU and @TheRawMeatball).
Solutions 1 is clearly a poor fit. Solution 2 comes with performance costs (hundreds of tiny, fragmented vecs, recomputation) and hurts conceptual clarity. Solution 3 is probably fine, but can result in broad queries and doesn't leverage the ECS super well (e.g. for data fragmentation).
Regardless of the solution that we reach consensus on as best-practice, we should make sure it's properly supported and has good examples. These patterns are surprisingly tricky, and I've seen various complaints about how hard these designs are to implement in ECS.
Additional context
This challenge / pattern was brought up in the context of widgets, prompting this issue.
The pattern selected here should be used when designing our UI framework: see #254.