Systems
Systems in an ECS are typically queries.
So you can still use the world.Query<Position, Velocity>() shown in the "Hello World" example.
Using Systems is optional but they have some significant advantages.
System features
Enable chaining multiple decoupled QuerySystem classes in a SystemGroup. Each group provide a CommandBuffer.
A system can have state - fields or properties - which can be used as parameters in
OnUpdate(). The system state can be serialized to JSON.Systems can be enabled/disabled or removed. The order of systems in a group can be changed.
Systems have performance monitoring build-in to measure execution times and memory allocations. If enabled systems detected as bottleneck can be optimized. A perf log (see example below) provide a clear overview of all systems their amount of entities and impact on performance.
Multiple worlds can be added to a single SystemRoot instance.
root.Update()will execute every system on all worlds.
Example
The example shows the setup of a small system hierarchy. Multiple systems can be added to a system hierarchy.
public static void HelloSystem()
{
var world = new EntityStore();
for (int n = 0; n < 10; n++) {
world.CreateEntity(new Position(n, 0, 0), new Velocity(), new Scale3());
}
var root = new SystemRoot(world) {
new MoveSystem(),
// new PulseSystem(),
// new ... multiple systems can be added. The execution order still remains clear.
};
root.Update(default);
}
class MoveSystem : QuerySystem<Position, Velocity>
{
protected override void OnUpdate() {
Query.ForEachEntity((ref Position position, ref Velocity velocity, Entity entity) => {
position.value += velocity.value;
});
}
}A valuable strength of an ECS is establishing a clear and decoupled code structure.
Adding the PulseSystem below to the SystemRoot above is trivial.
This system uses a foreach (var entity in Query.Entities) as an alternative to Query.ForEachEntity((...) => {...})
to iterate the query result.
The example also shows how to set a Filter in a system constructor to limit the query result to entities matching this Filter.
See all available filters at the QueryFilter - API.
The system hierarchy can be modified at runtime. New systems can be added, inserted or removed.
To prevent running a system when executing Update() without changing the hierarchy a system can be disabled with
System monitoring
System performance monitoring is disabled by default. To enable monitoring call:
When enabled system monitoring captures
Number of system executions.
System execution duration in ms.
Memory heap allocations per system in bytes.
The number of entities matching a query system.
Realtime monitoring
In a game editor like Unity system monitoring is available in the ECS System Set component.
Log monitoring
The performance statistics available at SystemPerf. To get performance statistics on console use:
The log result will look like:
SystemRoot
The SystemRoot is a container of systems forming a hierarchy of systems.
These systems are executed in their specified order.
Typically a SystemRoot operates on single EntityStore passed to its constructor.
A system hierarchy can also operate on multiple EntityStore's.
Additional stores are added with root.AddStore().
If needed a system hierarchy can be setup without any EntityStore.
This enables creating the hierarchy without the need of an EntityStore at initialization phase.
Update Execution
Execution of systems start always with the SystemRoot. Info - a SystemRoot is a SystemGroup.
Its child systems are executed when calling root.Update().
The child systems of a SystemGroup are executed in the order added to the group.
Each QuerySystem can override the following methods.
The execution of these methods of the group children is shown in the pseudo below.
Each group has a single CommandBuffer per EntityStore.
CommandBuffer.Playback() is called after execution of all OnUpdate() methods.
Execution order using a single EntityStore.
Execution order when using multiple EntityStore's.
Customize Systems
In cases a system requires code which goes beyond common Query execution a system can be customized.
Therefor a system can override OnAddStore()
Use cases for custom systems are:
Handle user input.
Moving the Camera. E.g. based on user input.
Execute multiple / nested queries in a single system. E.g. to detect collisions between two different entity sets and iterating both sets in nested loops.
Need to make structural changes via the parent group
CommandBuffer.Want direct access to an
EntityStore.
Extend QuerySystem
QuerySystemExample show how to extend a QuerySystem and execute a customQuery.
A QuerySystem enable access to the CommandBuffer.
Extend BaseSystem
BaseSystemExample shows how to extend a BaseSystem to call arbitrary methods on the EntityStore.
In this case to deal with UniqueEntity's.
Note: A BaseSystem has no access to the CommandBuffer.
Last updated
