-
-
Notifications
You must be signed in to change notification settings - Fork 96
EntityStructs and EntityViewStructs
The concept of EntityViewStructs is a very unique feature of Svelto, but the reasons behind their use are fundamentally different than the ones behind the use of EntityStructs.
EntityViewStructs are the way Engines see Entities. Different EntityViewStructs can re-interpret the same data through the use of components (and their implementors). EntityStructs are instead just pure data that cannot be re-intepreted according the engine and must be used as they are. The reasoning behind EntityViewStructs and EntityStructs is very different, however EntityStructs allow cache friendly code and 0 allocation code. EntityStructs also involve way less boilerplate code to be used. In general EntityStructs are always to prefer over EntityViewStructs when OOP code must not be abstracted:
EntityStructs are super modular and consequentially very abstracted entity components. Although they are structs, they are meant to hold even just one information only. The same set of entity structs, even if generated by different entities, should be processed in the same way by the same engine. EntityStructs promote abstraction. EntityStructs must be preferred over EntityViewStructs when the latter don't provide any benefit.
EntityViewStructs have been historically seen in Svelto as the reinterpretation of the entity data to be used by the current engine. In a way they filter the entity components the engine can access to. EntityViewStructs are designed to be "fat", to have multiple components. However it's a good practice to have the implementors very modular. Instead to have a big CharacterImplementor , implementing N components, is better to have one implementor per component so that components and implementors can be re-used for other entities. EntityViewStructs are also a way to group entities. If you would design EntityViewStruct always in a modular ways, so that they define generic data, it would be impossible to query specific entities, unless ExclusiveGroups are used. Without a PlayerEntityViewStruct and an EnemyEntityViewStruct, but only modular PositionEntityViewStruct and HealthEntityViewStruct, it would be impossible to iterate through enemies and players inside specialized engines without using specific ExclusiveGroups. However using ExclusiveGroups and Modular Entity Structs is the way to go, so this reasoning is here just because you may end up realising the same. EntityViewStructs implementors can also enable interesting patterns that are especially useful when performance is not a problem. However even when performance is a problem, using cache friendly EntityStructs may not always be the best solution. Let's assume we have a vehicle that can support different weapons. Each weapon has a shared cooldown value, as the weapons cannot fire again until the same cool down time is passed. Although this cool down value is the same for each weapon, I would be forced to store the same information once for each weapon and iterate all over them to set and read the same value. With implementors (which are references of objects), it is possible to create an entity (the vehicle in this case) that could share values with a set of other entities (the guns) though the use of the same Component and Implementor. Nowadays, EntityViewStructs and their components should be used only to abstract underlying platform dependencies or enable specific patterns. For example, consider the case of Unity and Monobehaviours, now imagine you want to write a game that is totally multithreaded. These implementors (as monobehaviours) would be usable on synchronization points, in the main thread, inside few engines. All the other multithreaded engines instead would use entity structs. The synchronization engines will read the entity struct values to be applied to the monobehaviour through the entity view structs. When thread-safe platform are used, then it's possible to be more flexible, but EntityStructs are still preferred for their data coherency and the fact that they are easily serializable.
More about it in my latest article (may be outdated):
http://www.sebaslab.com/svelto-ecs-2-5-and-allocation-0-code/
and this example:
https://github.com/sebas77/Svelto.ECS.Examples.CacheFriendlyECSWithEntityStructs