When working with gameObject, I usually seperate its visual (model, sprite, etc…) into child objects.
But in ECS it’s very tempting to put all relavent components on one single entity (physics, visuals, others), cause it allows you to query them super easily.
If I put visuals into child entities, whenever I want some data from for example ( render bounds) I need to iterate over my target entities, find their child buffers, access their child buffers to get render bounds components and access the data.
the process of including the child buffers leads to random access to components which seems to be a huge downside to me. it makes me feel I’m writing less ECS code but monobehaviour.
But seperation of logic and visual does a lot of benefits structually, although it feels against the concept of ECS by using multiple entities to represent one complex entity.
I’m struggling with the two ideas, I hope you could give me some advice for long-term development. Am I worrying too much on the performance loss ?
Probably. Always check the profiler. Maybe having child entities is already good enough.
You can run a job that collects these render bounds on a temporary native container. The job runs through the child entities instead of the main entity. This assumes that the child entity knows its main entity. Once collected, you can then pass these collection of render bounds unto your main job that runs through the main entities.
If you choose to split entities, you want to structure your splits to minimize the amount of communication between those entities. You can reduce communication (and thus the number of random accesses) by employing techniques like change filters and “pushing” changed values only when they change.
Without knowing more about your use case, it is hard for me to provide any more specific insight. There are lots of ways to tackle the problem, and none of them are silver bullets.
Do you think it’s reasonable to make visual as child entity? let’s say I have some animation systems that frequently access them and shrink them in scale, it seems reasonable to make it a child entity so I could simply modify its own localtransform without modifying collider size or other things, but some other data I need may reside in its parent enity (the visual only contains rendering related components) doing this requires constantly random access
How much data does it need from the parent? And how often does that data change? And how many of these entities do you have relative to the full scale of your game?
I’m making a vampire survivor like game (top-down shooter with lots of enemies)
I’m thinking about how to implement a hit feedback system, enemies that get shot will play some hit animation and some other effects.
My current damage system looks like:
Entities get hit will add a damage into their receivedDamage dynamic buffer, this buffer sits on the main entity (parent of its visual)
damage system iterates over all entites with this buffer and calculate their health loss, also enables a playHitAnim tag
hit feedback system iterates over all entities with playerHitAnim tag, then retrieve its visual (child entities), and tweak its scale somehow, disable playHitAnim tag when completed.
it’s not really the problem of how much data needed from the parent, in this architechture, I could only loop through the root entites (entities that contains damage buffer and other core data) because that’s where I could determine whether a character is hit or not. Unless I put visuals on the root as well (so everything in an entity)
This can happen very frequently due to player’s crazy fire rate and all sorts of AOE abilities.
So in this case, you are indeed “pushing” changes from the parent to the child, which as I mentioned earlier, is more optimal since you only need to do it for the entities that were actually hit. My suggestion then would be to try and put all the data on the child that the parent needs to write all in one component. That way, you only have one lookup and probably one random cache line to pull in to transfer the data.
Also, I highly doubt this random-access writing on change is going to be the bottleneck of your project. I suspect physics or rendering, or maybe animation (depending on how fancy you get) will hit you a lot harder than this logic.