Mix ‘n’ Match

I’ve written a bit about my entity-component system in the past, and about how I define entities and their components in my editor using XML markup. My editor defines a hierarchy of entities where the markup of each parent is prepended to one’s own. XML tags typically correspond 1:1 to components, and in the event that an entity and one of its ancestors both provide the same tag, the decision to append vs. overwrite can usually be inferred from context. (In some cases, when either option may be desirable, attributes can be used to make this explicit instead.)

hier_1
Sample entity hierarchy from Super Win

This served me well enough on Super Win the Game, but as I’ve started thinking seriously about content production for the Gunmetal Arcadia prequel (title to be revealed in Wednesday’s video; stay tuned), I’ve run into a few cases where a strict single-parent hierarchy just doesn’t make a whole lot of sense and has led to some redundant markup bloat.

Consider the case of things that may drop items. Enemies drop items when they die, but environmental things like torches and sconces do too. In order to avoid copying and pasting markup between these, and to ensure we keep them in sync if we decide to change how item drops work, it makes sense to parent each of these abstract entity definitions (enemies and environmental objects) to a base “item dropper” abstract entity definition.

hier_2
Proposed consolidation of item drop markup to a parent entity

But this introduces its own problems. What happens, for instance, when we want to generalize the concept of things that have AI between enemies and NPCs? Environmental objects like torches and sconces certainly don’t need AI, so it doesn’t make sense to derive the “item dropper” entity from this “AI driven” entity. But likewise, NPCs can’t die and will never drop items, so it doesn’t make sense to derive the “AI driven” entity from our “item dropper.”

hier_3
Not a good solution. Why is an item dropper necessarily AI-driven? Environmental objects require no AI.

 

hier_4
Also not a good solution. Why is an AI-driven thing also necessarily an item dropper? NPCs will never drop items.

What we really want is to be able to pick and choose from an arbitrary number of parent entities. In this way, we can treat these parents not as a strict hierarchy, but as more of a system of composable interfaces.

hier_5
A proposal for a better hierarchy. Note that our enemy entity now has two parents.

When I started implementing this, I was thinking about it in terms of multiple inheritance, but that term carries some baggage that doesn’t really apply here. In truth, neither “inheritance” nor “composition” is really an appropriate expression here, as these aren’t classes and don’t provide functions. This is simply a way of prepending associated data to a sheet of XML markup, and for the sake of familiarity, I’m thinking about it in terms of programming concepts.

My implementation is fairly simple: instead of a single parent entity definition, an entity may specify an arbitrary number of parents. The editor interface prevents loops by disallowing an entity’s own descendents from being selected as ancestors, but otherwise, anything is fair game. Conflicts or redundancies are avoided by explicitly specifying the order in which parents are evaluated. In the event that an entity is derived from A and B, each of which is derived from C, the resulting output could be either the concatenation of C-A-B or C-B-A. By requiring the order to be specified within the editor, these sorts of ambiguities are avoided.

hier_6
The editor tool for selecting parent entities.

This implementation gives me the freedom and flexibility to choose how I want to structure my data. My expectation is that as I start migrating existing content over to this new format and building new content on top of that, I’ll start to get a feel for best practices, and maybe that can be another blog somewhere down the road.