Simple to use Update Manager pattern for Unity + Jobified Update for MonoBehaviour
s and pure C# classes alike.
Using these may improve your game's CPU usage when there are thousands of objects updating every frame.
More info on Update Manager vs traditional Update: https://github.com/Menyus777/Game-engine-specific-optimization-techniques-for-Unity
UpdateManager
to call objects' ManagedUpdate
, ManagedLateUpdate
or ManagedFixedUpdate
method, bypassing Unity's native <-> C# interopBoth MonoBehaviour
and pure C# classes are supported, just implement IUpdatable
, ILateUpdatable
and/or IFixedUpdatable
interface and register the object to be updated using its RegisterInManager
extension method.
Remember to unregister the objects with UnregisterInManager
when necessary.
AManagedBehaviour
to automatically register/unregister MonoBehaviours in UpdateManager
in their OnEnable
/OnDisable
messages.
The class still needs to implement the IUpdatable
, ILateUpdatable
and/or IFixedUpdatable
interfaces for any managed update methods to be run.Job System:
UpdateJobManager<MyIUpdateJobStruct>
to run jobs every frame using Unity's Job systemUpdateTransformJobManager<MyIUpdateTransformJobStruct>
to run jobs with TransformAccess
every frame using Unity's Job system, so you can change your objects' transforms from jobsBoth MonoBehaviour
and pure C# classes are supported, just implement IJobUpdatable<MyIUpdateJobStruct>
or ITransformJobUpdatable<MyIUpdateTransformJobStruct>
interface and register the object to be updated using the RegisterInManager
extension method.
Remember to unregister the objects with UnregisterInManager
when necessary.
AJobBehaviour<MyIUpdateTransformJobStruct>
to automatically register/unregister MonoBehaviours for update jobs in their OnEnable
/OnDisable
messagesIBurstUpdateJob<BurstUpdateJob<MyJobStruct>>
instead of IUpdateJob
in your job struct type.
The same is true for IBurstUpdateTransformJob<BurstUpdateTransformJob<MyJobStruct>>
vs IUpdateTransformJob
.UpdateJobTime
class with information from Unity's Time
class that you can access from within jobs (deltaTime
, time
, etc...)[JobBatchSize(...)]
attribute in job structs.
This is ignored in read-write transform jobs.Add dependencies between managed jobs using [DependsOn(typeof(MyJobDependency1), ...)]
.
For now, no dependency cycle detection is performed, so job runners may get deadlocked if you misuse it.
UpdateManager
doesn't have the concept of script execution order like Unity MonoBehaviours, so don't rely on execution order.Read-write transform jobs are only parallelized if the objects live in hierarchies with different root objects. This is a limitation of Unity's job system.
Read-only transform jobs, marked by the [ReadOnlyTransformAccess]
attribute, don't have this restriction.
NativeArray
, NativeList
...) are supported in managed jobs, the thread safety system provided by Unity is not applied to them.
Use them with care!This package is available on the openupm registry and can be installed using the openupm-cli:
openupm add com.gilzoide.update-manager
Otherwise, you can install directly using the Unity Package Manager with the following URL:
https://github.com/gilzoide/unity-update-manager.git#1.5.2
Or you can clone this repository or download a snapshot of it directly inside your project's Assets
or Packages
folder.
UpdateManager
+ MonoBehaviour
using Gilzoide.UpdateManager;
using UnityEngine;
public class MyManagedUpdatableBehaviour : AManagedBehaviour, IUpdatable, ILateUpdatable, IFixedUpdatable
{
public void ManagedUpdate()
{
Debug.Log("Called every frame, alongside other scripts' Update message");
}
public void ManagedLateUpdate()
{
Debug.Log("Also called every frame, alongside other scripts' LateUpdate message");
}
public void ManagedFixedUpdate()
{
Debug.Log("Also called every frame, alongside other scripts' FixedUpdate message");
}
}
UpdateManager
with pure C# classusing Gilzoide.UpdateManager;
using UnityEngine;
public class MyUpdatable : IUpdatable, ILateUpdatable, IFixedUpdatable
{
public void ManagedUpdate()
{
Debug.Log("Called every frame, alongside other scripts' Update message");
}
public void ManagedLateUpdate()
{
Debug.Log("Also called every frame, alongside other scripts' LateUpdate message");
}
public void ManagedFixedUpdate()
{
Debug.Log("Also called every frame, alongside other scripts' FixedUpdate message");
}
// call this when you want Updates to start running
public void StartUpdating()
{
this.RegisterInManager();
// ^ alias for `UpdateManager.Instance.Register(this)`
}
// call this when necessary to stop the updates
public void StopUpdating()
{
this.UnregisterInManager();
// ^ alias for `UpdateManager.Instance.Unregister(this)`
}
}
UpdateTransformJobManager
+ MonoBehaviour
using System.Collections;
using Gilzoide.UpdateManager.Jobs;
using UnityEngine;
using UnityEngine.Jobs;
// 1. Create the Job struct
//
// Note: Implement `IBurstUpdateTransformJob<BurstUpdateTransformJob<MoveJob>>`
// instead if you want Burst to compile the job
public struct MoveJob : IUpdateTransformJob
{
public Vector3 Direction;
public float Speed;
public bool SomethingHappened;
public void Execute(TransformAccess transform)
{
Debug.Log("This will be called every frame using Unity's Job system");
// This runs outside of the Main Thread, so
// we need to use `UpdateJobTime` instead of `Time`
float deltaTime = UpdateJobTime.deltaTime;
// You can modify the Transform in jobs!
transform.localPosition += Direction * Speed * deltaTime;
// You can modify the struct's value and fetch them later!
SomethingHappened = true;
}
}
// 2. Create the job-updated behaviour
public class MyJobifiedBehaviour : AJobBehaviour<MoveJob>
{
// set the parameters in Unity's Inspector
public Vector3 Direction;
public float Speed;
// (optional) Set the data passed to the first job run
public override MoveJob InitialJobData => new MoveJob
{
Direction = Direction,
Speed = Speed,
};
IEnumerator Start()
{
// wait a frame to see if something happened
yield return null;
// use the `JobData` property to fetch the current data
MoveJob currentData = JobData;
// should print "Something happened: true"
Debug.Log("Something happened: " + currentData.SomethingHappened);
}
}
UpdateJobManager
+ pure C# classusing Gilzoide.UpdateManager.Jobs;
using UnityEngine;
// 1. Create the Job struct
//
// Note: Implement `IBurstUpdateJob<BurstUpdateJob<MoveJob>>`
// instead if you want Burst to compile the job
public struct CountJob : IUpdateJob
{
public int Count;
public void Execute()
{
Debug.Log("This will be called every frame using Unity's Job system");
Count++;
}
}
// 2. Create the job-updated class
public class MyJobifiedBehaviour : IJobUpdatable<CountJob>
{
// Set the data passed to the first job run
public CountJob InitialJobData => default;
// call this when you want Updates to start running
public void StartUpdating()
{
this.RegisterInManager();
// ^ alias for `UpdateJobManager<CountJob>.Instance.Register(this)`
}
// call this when necessary to stop the updates
public void StopUpdating()
{
this.UnregisterInManager();
// ^ alias for `UpdateJobManager<CountJob>.Instance.Unregister(this)`
}
// fetch current data using `this.GetJobData`
public int CurrentCount => this.GetJobData().Count;
}