How do we consider Data entities with game object representation? Currently making a hack and slash project where we have game object for animated 3d models using the animator still as there is no direct replacement for the animator at this time.
I am currently implementing a hybrid approach. By that I mean NOT using entities but using simple struct arrays for “Actors” so it should be relatively straightforward to Job-ify the code.
I created an “Actors” system which let’s me spawn an instance from a prefab, which is automatically pooled as well and gets an index in the collection. Actors are also despawned through the same system. The actual GameObject has as little components on it as possible, eg typically visual stuff like Animator or a script that holds references to child objects such as IK bones or the parent for weapons (right-hand bone).
Each actor uses an IActor interface so that the class encoding the actor is guaranteed to have a reference to the GameObject, as well as the data asset (a ScriptableObject) and an actor index. All actors are maintained in a collection of their own kind (eg enemies). And they have “System” scripts that run their logic, and other things. The animator just applies the data of the ActorRuntimeData.
Then, for runtime data I just add a struct called eg ProjectileRuntimeData to that IActor class. This contains all the runtime-only variables such as the current “end of live” time or impact info (collider, hit point).
Sometimes, you only get a GameObject reference. Mainly collisions. For this, the Actor spawn system also requires that each prefab has a ActorIdentity script in its root, which contains both the ActorIndex and the CollectionIndex - the latter is to distinguish between projectiles, enemies, and so on. Now when you collide you can GetComponent() on the collider and then look up the actor by its index and forward the collision to the appropriate impact response script that is attached to the (single) Actor collection object.
While this isn’t perfectly separating everything it should be good enough for a later port to Jobs, and perhaps even entities.
Point worth considering: all structs are passed by ref so they won’t incure copy costs nor bugs due to not writing back. You can have a ref indexer and get the value like so:
ref var actor = ref actors[index];
actor.propery = 10; // value is changed in-place, no write-back needed!