index
#] Systems
Construct defines a System as a global object that is always accessible at runtime independently of the current active Scene as long as their container scene is loaded. To achieve this behaviour, this library allows developers to create, initialize and manage all the required Systems (both Construct built-in and custom) through the definition of a single Unity Scene and the use of the Systems static class.
Project setup
In order to use the various Systems, it is required to create a new Scene with an arbitrary name. From now on let's suppose it's called Systems.
Manual setup
The Systems Scene defines what Systems are available at runtime, by defining a series of GameObjects that are going to be always accessible by the other scripts using the Singleton pattern (if they extend BaseSystem) or through the Systems static class (If they only implement the ISystem interface.)
// Get it from the Instance static property if SystemType extends BaseSystem.
SystemType system = SystemType.Instance;
// Get it from the Systems class if SystemType is a BaseSystem or implements ISystem.
system = Systems.GetSystem<SystemType>();
// Try to get it from the Systems class if it exists
var exists = Systems.TryGetSystem(out system);
Each System is placed on a different GameObject that must be the root of its own hierarchy. They can have eventual children, but the System itself has to be on the root.
The Systems scene hierarchy should contain an arbitrary number of System objects. The specific number of different Systems in the scene depends on the number of Construct packages installed; below an example with Core, Events and Persistence packages installed:
Automated setup
It's also possible to automatically create the Systems scene through the Menu bar, by clicking Construct > Create > Systems Scene. This creates a Scene asset called Systems inside the _Scenes folder (it will be created if it doesn't exist) and it adds the new Scene to the active Scenes List.
The new scene contains all known Systems on their respective GameObject. The number and types of the added Systems depend on the number of installed Construct packages that define a System and how many custom systems are present.
It's recommended to create prefabs for the System objects, this way the Systems Scene doesn't have to be modified unless a new System is added or one is removed.
Loading Systems at runtime
The easiest way to load all Systems at once is to call Systems.Load() before any other operation that requires a System to be ready. It returns a YieldInstruction and thus can be used in a Coroutine:
private IEnumerator Start()
{
yield return Systems.Load();
Debug.Log($"Systems ready = {Systems.Ready}");
// Operations after systems are ready
}
But it also accept a callback as a parameter.
System.Load(ready => Debug.Log($"Systems ready = {ready}"));
Systems are loaded in parallel, but if there are dependency constaints, they can be grouped by setting their Priority value in the Inspector. Smaller values mean more priority. By default, the value of priority of all Systems is 0.
Systems.Load has an overload that accept the name of the Systems scene. It must be used when the Systems scene is not called Systems.
Systems.Load("MySystemsScene");
Systems.Load("MySystemsScene", ready => Debug.Log($"Systems ready = {ready}"));
A call to any overload of Systems.Load returns imediately if Systems.SceneIsReady is already true.
Run and Shutdown Systems
All Systems will be running after the call to Systems.Load finishes executing, but all individual Systems can be shutdown by calling either their Shutdown method or by calling
Systems.TryShutdown<TSystem>(out var yieldShutdownInstruction)
In the same way they can be run again by calling either their Run method or by calling
Systems.TryRun<TSystem>(out var yieldRunInstruction)
See the reference for more information.
Non-MonoBehaviour Systems
Custom Systems can be implemented by either extending BaseSystem<TSystem> (where TSystem is the type of the System itself), making it a MonoBehaviour to put in the Systems Scene, or by implementing ISystem, allowing a more "manual" handling.
In this second scenario, the System must be manually registered by calling
Systems.TryRegister(mySystem, true, out YieldInstruction yieldRunInstruction)
If the second parameter is true, it will automatically run the System if it's not running yet. Pass false if you don't want it to run yet. yieldRunInstruction will be null if the System already exists (it returns false) or if it tried to run it but the System was already running (it returns true.) See the reference for more information.