Skip to content

Latest commit

 

History

History
115 lines (73 loc) · 10.7 KB

systems.md

File metadata and controls

115 lines (73 loc) · 10.7 KB

Systems

A system is a unit of code which belongs to a world and which runs on the main thread (usually once per frame). Normally, a system will only access entities of its own world, but this is not an enforced restriction.

🕹 See example systems.

A system is defined as a struct implementing the ISystem interface, which has three key methods:

ISystemState method Description
OnUpdate() Normally called once per frame, though this depends upon the SystemGroup to which the system belongs.
OnCreate() Called before the first call to OnUpdate and whenever a system resumes running.
OnDestroy() Called when a system is destroyed.

A system may additionally implement ISystemStartStop, which has these methods:

ISystemStartStop method Description
OnStartRunning() Called before the first call to OnUpdate and after any time the system's Enabled property is changed from false to true.
OnStopRunning() Called before OnDestroy and after any time the system's Enabled property is changed from true to false.

System groups and system update order

The systems of a world are organized into system groups. Each system group has an ordered list of systems and other system groups as its children, so the system groups form a hierarchy, which determines the update order. A system group is defined as a class inheriting from ComponentSystemGroup.

🕹 See example system groups.

When a system group is updated, the group normally updates its children in their sorted order, but this default behavior can be overridden by overriding the group's update method.

A group's children are re-sorted every time a child is added or removed from the group.

The [UpdateBefore] and [UpdateAfter] attributes can be used to determine the relative sort order amongst the children in a group. For example, if a FooSystem has the attribute UpdateBefore(typeof(BarSystem))], then FooSystem will be put somewhere before BarSystem in the sorted order. If, however, FooSystem and BarSystem don't belong to the same group, the attribute is ignored. If an ordering attribute contradicts another, an exception is thrown.


Creating worlds and systems

By default, an automatic bootstrapping process creates a default world with three system groups:

  • InitializationSystemGroup, which updates at the end of the Initialization phase of the Unity player loop.
  • SimulationSystemGroup, which updates at the end of the Update phase of the Unity player loop.
  • PresentationSystemGroup, which updates at the end of the PreLateUpdate phase of the Unity player loop.

The systems and system groups will normally be added to the SimulationSystemGroup, but this can be overridden by marking them with the [UpdateInGroup] attribute. For example, if a FooSystem has the attribute UpdateInGroup(typeof(InitializationSystemGroup))], then FooSystem will be added to the InitializationSystemGroup instead of the SimulationSystemGroup. A system or system group with the [DisableAutoCreation] attribute will not be instantiated by the automatic bootstrapping.

The automatic bootstrapping process can be disabled with scripting defines:

Scripting define Description
#UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP_RUNTIME_WORLD Disables automatic bootstrapping of the default world.
#UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP_EDITOR_WORLD Disables automatic bootstrapping of the Editor world.
#UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP Disables automatic bootstrapping of both the default world and the Editor world.

When automatic bootstrapping is disabled, your code is responsible for:

  • Creating any worlds you need.
  • Calling World.GetOrCreateSystem<T>() to add the system and system group instances to the worlds.
  • Inserting updates of the top-level system groups (e.g. SimulationSystemGroup) into the Unity PlayerLoop.

Alternatively, automatic bootstrapping can be customized by creating a class that implements ICustomBootstrap.

🕹 See examples of world creation and customized bootstrapping.


Time in worlds and systems

A world has a Time property, which returns a TimeData struct, containing the frame delta time and elapsed time. The time value is updated by the world's UpdateWorldTimeSystem. The time value can be manipulated with these World methods:

World method Description
SetTime Set the time value.
PushTime Temporarily change the time value.
PopTime Restore the time value from before the last push.

Some system groups, like FixedStepSimulationSystemGroup, push a time value before updating their children and then pop the value once done updating. Systems in these groups effectively see the pushed time value.


SystemState

The SystemState parameter of a system's OnUpdate(), OnCreate(), and OnDestroy() methods represents the state of the system instance and has important methods and properties, including:

Method or property Description
World The system's world.
EntityManager The EntityManager of the system's world.
Dependency A JobHandle used to pass job dependencies between systems.
GetEntityQuery() Returns an EntityQuery.
GetComponentTypeHandle<T>() Returns a ComponentTypeHandle<T>.
GetComponentLookup<T>() Returns a ComponentLookup<T>.
⚠ IMPORTANT
Although entity queries, component type handles, and component lookups can be acquired directly from the EntityManager, it is generally proper for a system to only acquire these things from the SystemState instead. By going through SystemState, the component types accessed get tracked by the system, which is essential for the Dependency property to correctly pass job dependencies between systems. See more about jobs that access entities.

SystemAPI

The SystemAPI class has many static convenience methods, covering much of the same functionality as World, EntityManager, and SystemState.

The SystemAPI methods rely upon source generators, so they only work in systems and IJobEntity (but not IJobChunk). The advantage of using SystemAPI is that these methods produce the same results in both contexts, so code that uses SystemAPI will generally be easier to copy-paste between these two contexts.

📝 NOTE
If you get confused about where to look for key Entities functionality, the general rule is to check SystemAPI first. If SystemAPI doesn't have what you're looking for, look in SystemState, and if what you're looking for isn't there, look in the EntityManager and World.

SystemAPI provides a special Query() method that, through source generation, helps conveniently create a foreach that loops through the entities and components matching a query.

🕹 See examples of using SystemAPI.Query().