General
Unity has a built-in system for handling update loops called the PlayerLoop. The PlayerLoop consists of nested PlayerLoopSystems and each of them handle a specific part of updating a frame in Unity. The most common one is the PlayerLoopSystem called ScriptRunBehaviourUpdate that calls all the Update methods of the MonoBehaviour scripts in the scene.
This asset comes with tools, prefabs and Editor views to easily add, remove and monitor parts of the PlayerLoop.
The asset package consists of logic scripts, editor scripts and some examples. You can have full control of the features with minimal coding: there are prefabs included for common use cases and most features can be accessed in the Editor inspector view. All of the features can of course be used from code too.
Features
- Create custom update loops and run them at any stage of the PlayerLoop
- Drag 'n drop a prefab to create a custom loop and select its callback method(s) in Editor
- Or create it in code - AdvancedUpdateLoops.CreateCustomUpdateLoop()
- Editor view for monitoring and customising the PlayerLoop
- Add and remove update loops during play mode in Editor
- Remove default loops and save the configuration to an asset file
- Set the saved config in Editor to apply it on every app start
- Created custom loops appear in the profiler for performance monitoring
- Ready prefabs for PreUpdate, PostUpdate, PreLateUpdate, PostLateUpdate, PreFixedUpdate and PostFixedUpdate
Using the prefabs and editor views
You can find pre made prefabs for all of the features inside folder Assets/Vuopaja/UpdateLoops/Prefabs. There are prefabs for the UpdateLoopManager and common use cases of custom loops. The UpdateLoopManager script is not required for adding custom loops but it gives us the functionality to modify the PlayerLoop in the Editor and to use a config asset to apply a saved PlayerLoop configuration.
The custom loop prefabs have a CustomUpdateLoopMono script attached which creates a custom loop as it is configured in the inspector view. Additionally they have an example script that only logs the name of the method in the console every update of the loop. The CustomUpdateLoopMono script has the following configurable properties:
- LoopName - Free text name for this loop which is displayed in UpdateLoopManager and Unity Profiler.
- SelectedPlayerLoop - Button which opens a dropdown menu to select a default PlayerLoopSystem that we want to add this custom loop next to.
- InsertBehaviour - Dropdown menu for either “Before Selected” of “After Selected”. Defines if this custom loop should be run before or after the previously selected PlayerLoopSystem.
- Callback Method(s) - List of callbacks that can be configured to listen to this custom loop. These will be invoked every frame exactly at the position in the player loop that was specified with SelectedPlayerLoop and InsertBehaviour.
Other functionality of this package can be found in the UpdateLoopManager script. You can add this script to any GameObject in the scene; in the examples it is added to an empty one called UpdateLoopManager. The UpdateLoopManager has the following properties:
- Config - An optional configuration file that can be created with this editor view. The config is applied on app start and it can be used to disable default PlayerLoopSystems.
- Active PlayerLoopSystems - A toggle list that displays all currently active PlayerLoopSystems. Use the “-” button to disable a PlayerLoopSystem. Only visible when in play mode.
- Disabled PlayerLoopSystems - A toggle list that displays all disabled default PlayerLoopSystems. Use the “+” button to re-enable a PlayerLoopSystem in this list. Only visible when in play mode.
- Save Config As - Button to save the disabled list to an asset file that can be assigned to the Config property on this script.
Using the features from code
All features are accessible from code in the AdvancedUpdateLoops class. The class has the following publicly accessible static methods:
// in the current PlayerLoop.
Action PlayerLoopUpdated;
// Create and start a new custom update loop.
// Parameters:
// name - Free text name for this loop
// selectedName - Name of the default PlayerLoopSystem that we want to add this custom loop next to.
// insertBehaviour - Either BeforeSelected or AfterSelected
// callback - An action for listening the callbacks from this loop
void CreateCustomUpdateLoop(string name, string selectedName, InsertBehaviour insertBehaviour, Action callback)
// Remove a PlayerLoopSystem by name.
void RemovePlayerLoopSystem(string name)
// Remove a PlayerLoopSystem by type.
void RemovePlayerLoopSystem(Type type)
// Re-add a default PlayerLoopSystem by name.
void ResumeDefaultPlayerLoopSystem(string name)
// Re-add a default PlayerLoopSystem by type.
void ResumeDefaultPlayerLoopSystem(Type type)
// Check if provided name equals with added custom loop type.
bool IsCustomUpdateLoop(string name)
// Check if provided type equals with added custom loop type.
bool IsCustomUpdateLoop(Type type)
// Check if a default PlayerLoopSystem is currently active by name.
bool IsPlayerLoopSystemActive(string name)
// Check if PlayerLoopSystem is currently active by type.
bool IsPlayerLoopSystemActive(string name)
Examples
The package has three example scenes included. The scenes are located in their own folders under Assets/Vuopaja/UpdateLoops/Examples/.
CustomUpdateLoopExample
The CustomUpdateLoopsExample shows us how we can have multiple custom loops running in the scene. Run the scene to see the custom loops logging in the console.
There are custom loops for PreUpdate, PostUpdate, PreLateUpdate, PostLateUpdate, PreFixedUpdate and PostFixedUpdate. The custom loop prefabs have a CustomUpdateLoopMono script attached which creates a custom loop as it is configured in the inspector view. Additionally they have an example script that only logs the name of the method in the console every update of the loop.
The scene can be recreated from scratch simply by creating the scene and dragging in the custom loop prefabs from Assets/Vuopaja/UpdateLoops/Prefabs.
UpdateLoopManagerExample
The UpdateLoopManagerExample shows us how we can use an UpdateLoopConfig asset to disable default loops on app start. The UpdateLoopManager GameObject also has a UpdateLoopManagerExample script attached. That script has implemented the Update, LateUpdate and FixedUpdate methods and each of the methods log the name of the method to console on every update. But as the UpdateLoopManager is configured with an UpdateLoopConfig asset that has ScriptRunBehaviourUpdate, ScriptRunBehaviourLateUpdate and ScriptRunBehaviourFixedUpdate disabled we see no messages in the console when running the scene.
You can try to resume the disabled PlayerLoopSystems using the UpdateLoopManager inspector view and as soon as the PlayerLoopSystems are resumed you start to see the logs as expected. To resume a PlayerLoopSystem just toggle open the "Disabled PlayerLoopSystems" list and click the "+" button next to the PlayerLoopSystem you want to resume.
PhysicsToggleExample
The PhysicsToggleExample shows us how we can use the features from code. The scene has a GameObject which has UpdateLoopManager and PhysicsToggleExample scripts attached. The example script spawns cubes with rigidbodies periodically. Rigidbodies are used to enable Unity physics on the cubes. The physics system is updated by a PlayerLoopSystem called PhysicsFixedUpdate. The example shows how you can pause/resume physics by removing/adding the PhysicsFixedUpdate PlayerLoopSystem.
The example UI has a button that is linked to call a method called TogglePhysics in the example script. The method calls RemovePlayerLoopSystem or ResumePlayerLoopSystem depending on the current state. All the changes can be monitored by looking at the UpdateLoopManager inspector view. You can see how the PhysicsFixedUpdate PlayerLoopSystem is moving between active and disabled lists when the UI button is clicked.
The example script also shows how we can listen for changes in the PlayerLoop by using the PlayerLoopUpdated event action. The example registers an event listener in the Start method and the playerLoopUpdated callback is called every time a change is made to the PlayerLoop. Inside the callback it checks the state of the PhysicsFixedUpdate PlayerLoopSystem by calling IsPlayerLoopSystemActive method. Then it updates the example UI to reflect the current state.
Compatibility
This asset is tested to be compatible with Unity versions 2020.3 and newer. Earlier versions may also work but are not fully tested. All build targets are also supported.
There are a few limitations in naming the PlayerLoopSystems on some setups. By default the name given while creating the custom loop is used to make a new dynamic type that is used in the PlayerLoopSystem. Platforms that use AOT compilation (IL2CPP) cannot define dynamic assemblies. This means that custom loops are named using pre defined static types in Assets/Vuopaja/AdvancedUpdateLoops/Scripts/CustomTypes.cs file. There are 20 custom types pre made but if you need more you can just declare more types there with this naming convention: CustomUpdateLoop_INDEX where INDEX is a running integer.
The same limitation applies on Unity versions below 2021. They use the .NET Standard 2.0 API compatibility level that doesn’t support dynamic assemblies. The same static typing workaround is used on .NET Standard 2.0 but if you want to have dynamic names for your custom loops you can switch to .NET 4.x in the project settings.
The static naming only affects the name visible in UpdateLoopManager and profiler. All features still work without dynamic typing.
Questions
Be sure to check out the Frequently Asked Questions for common questions about Advanced Update Loops.
If you have any other questions click here for contact information.