In Amethyst, "animation" does not simply mean visual animation; it means any sort of data that can morph over a certain input value such as time.
When using Amethyst, animation is designed to be done per Component, e.g. we can morph the
SpriteRender, or alter the local Transform component. Therefore, if you structure your
application's configuration with a different data hierarchy, you should process it into the
Component type.
In Will's game configuration, Every object has a series of Sequences, each sequence has
a Vec<ObjectFrame>.
Each ObjectFrame contains multiple parts:
- Sprite
- Body
- Interactions
- Potentially more, such as weapon position
These are intended to change frame by frame, in sync with each other.
The question arises, should we have ObjectFrame as a Component, which means we have a single
Animation<ObjectFrame>, or should we create Components for each of these configuration
parts?
A top level Animation<ObjectFrame> means, when we add separate configuration parts, we do not
need to create separate Component types for each of these parts. Systems that use a
configuration part will access it either via ReadStorage<'s, ObjectFrame>, or there must be an
intermediate system that reads the ObjectFrames and writes the individual Components for all
entities. Note that this design means animation is strictly Step interpolated, so each part is
discreetly calculated.
Separate Components means writing separate Animation<_> types for each component, and
processing the configuration into those types. Each of the animations are run at the same time
to keep them in sync with each other (same time input value). Systems that use a
configuration part will access it via ReadStorage<'s, Component>. This design allows separate
components to have separate interpolation. However, if Components are all going to be Step
interpolated, then this introduces a lot of additional effort for which the value is not
applicable.
The following table compares the development implications for the two design choices:
| Item | Frame Component Animation | Multi Component Animation |
|---|---|---|
| Effort - Addition | Lower | Higher - process config into Component |
| Performance | No duplication of interpolation | Duplicates interpolation |
| Performance | Bottleneck with splitter System |
- |
| Performance | Poor data locality for systems | Good data locality (read component) |
| System Data | Unclear if no splitter system | Clear |
| Compilation | Extra(?) if no splitter system | Generation of animation component types |
There may be more that I haven't thought of right now.
Animation primitives are Copy + Serializable, which means we cannot simply pass references to
the active ObjectFrame or component. This means we may have to generate a HashMap<u64, _>,
where _ is either &ObjectFrame or &Component, or Handles to each, in order to not
clone() the data in memory.