0
\$\begingroup\$

In Unity (and I presume other game engines) you can create "prefabs" which are blueprints for game objects. They contain a list of components, and default values for those components. Prefabs can be instantiated many times, which is an efficient way of creating many objects of the same kind.

One feature in particular of prefabs is that you can modify an attribute on a single instance of a prefab, without modifying the prefab itself. Similarly, you can modify the prefab, which will propagate the change to all instances.

I've been working on an implementation of the Entity Component System (for a high-level description of ECS see this question: How to implement n-body in an Entity Component System), and I got stuck on how to implement prefabs efficiently in ECS. I think it's a powerful capability of EC-design, and implementing this on native ECS would be awesome.

I can come up with a few approaches:

  • Create archetypes, which are predefined lists of components (Unity approach). This does not let me set initial values for the components, nor override them (there is nothing to override). Easy to implement, but doesn't really do what I want it to do.
  • Create a "prototype" entity from which other entities are cloned, including component values. With this design I can override individual attributes, but when I update the prototype, the clones don't get updated.
  • Create entities with a reference to a "base" entity. When getting a component from an entity, first look in its component list, then try the base entity. This way when I update a base component, base instances change as well. To override a base component I can simply add it to the instance entity.

Of these three approaches the third approach comes closest, but I don't see a straightforward way to extend it so I can override a single attribute. How can I make this work?

\$\endgroup\$
0
\$\begingroup\$

The trick to this is that Unity's prefabs aren't strictly part of its component system (though they use features of components). They're part of its serialization system.

Try setting Unity's asset serialization mode to "Force Text" and examine a scene file in a text editor to see this in action.

The serialized version of a game object inside the scene references that object's prefab, as well as listing any parameters that have been overridden from the prefab.

When you open a scene, exit play mode, or make a change to a prefab, Unity's deserializer populates each of those instances by first creating a clone of the prefab's data (like your prototype example), then overwriting each parameter that the instance being deserialized overrides, as described in its serialized record.

The inspector can read this serialized data (or an equivalent in-memory structure) to know which fields to draw in the overridden style or inherited style. When you change an inherited field, it can be added as another override to record when serializing the instance. When you click "revert", Unity clears all override notes associated with the instance.

Nowhere in this process do the components themselves have any concept of inheritance or overriding of their fields. That layer can be applied completely external to the component system, used at runtime only when an object in a scene (or the new nested prefabs) needs to be deserialized. (Though this inheritance could presumably get "baked out" at build time and avoid any runtime inheritance of component parameters at all)

|improve this answer|||||
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.