According to the documentation: “The order in which Unity calls each GameObject’s Awake is not deterministic. Because of this, you should not rely on Awake being called on one GameObject before or after another.”
I can confirm that the order changes for me when hitting play in the editor vs reloading the scene via
SceneManager.LoadSceneAsync().
Is there a way to guarantee the sequence of some method call in different game objects?
For example, I have:
private void Awake() { EntityManager.Instance.Register(this) }
Register will add the object to a list, I want this list to always have the same order.
I need to replace Awake by a method that will be called on each game object by some class that will guarantee the calls order. That relies on being able to order game objects somehow.
I can’t order then by name because I may have objects with the same name. I can’t order by Instance ID because that changes on every run.
I thought I could get the root objects and go through each child so that would be the order in the hierarchy. However I don’t know if Scene.GetRootGameObjects() is guaranteed to return roots in the same order. Probably not but does it matter? What are the different root objects when there’s only 1 scene loaded?
Across different types of components, there is the Script Execution Order settings. Across the same component type, I don’t believe so.
To achieve this you usually need to introduce your own system that can guarantee order. How you do so really depends on the particular of your project.
If I had a number of game objects in a scene I wanted to be registered to some top-level entity, I would probably either:
Add my own data point that they can be sorted by
Make a ‘group’ component that can serialise references to all the necessary components across child game objects, with some simple editor scripts to automate this. Which then registers them in the order they are referenced (or sorted by).
I like your idea of having a script that will reference game objects during edit time so it’s always the same order when I run, thank you. But I wish there was a way to do it automatically during runtime.
EDIT - to explain wtf I’m going on about here
You’re going to have to define the order some way. May it be by inserting it into that list in its appropriate spot or sorting by some int value that is configured. You could do this at editor time or at runtime though it could get convoluted.
Here I’ll go into a way to accomplish this on a per GameObject process with an ‘order’ script. OnEnable this will insert itself into the global list at runtime.
If you want to configure it note that I didn’t write specific support for modifying ‘Order’ while the script is enabled and active. You’ll have to disable it… modify the order… then re-enable it.
/END EDIT
Place something like this onto a GameObject to define that GameObjects order.
using UnityEngine;
using UnityEngine.LowLevel;
using System.Collections.Generic;
public class SynchronizedUpdater : MonoBehaviour
{
#region Static Interface
static bool _initialized = false;
static void TryStartCustomPlayerLoop()
{
if (_initialized) return;
_initialized = true;
var loop = PlayerLoop.GetCurrentPlayerLoop();
var arr = new PlayerLoopSystem[loop.subSystemList.Length + 1];
System.Array.Copy(loop.subSystemList, arr, loop.subSystemList.Length);
arr[arr.Length - 1] = new PlayerLoopSystem()
{
type = typeof(SynchronizedUpdater),
updateDelegate = PoolUpdateCallback,
};
loop.subSystemList = arr;
PlayerLoop.SetPlayerLoop(loop);
}
static readonly List<SynchronizedUpdater> Pool = new();
static void Register(SynchronizedUpdater obj)
{
//NOTE - this is a really naive insertion approach, should probably go with a BinaryHeap or something if you have an implementation laying around.
for (int i = 0; i < Pool.Count; i++)
{
var o = Pool[i];
if (o == obj) return; //collection already contains the obj
if (o.Order > obj.Order)
{
Pool.Insert(i, obj);
return;
}
}
Pool.Add(obj);
}
static void Unregister(SynchronizedUpdater obj)
{
Pool.Remove(obj);
}
static void PoolUpdateCallback()
{
//NOTE - I have not written any code pertaining to ensuring the 'Pool' doesn't change during SynchronizeUpdate.
//It's a bad idea to disable a GameObject during SynchronizedUpdate else this will throw an exception unless you write logic to handle that scenario
foreach (var obj in Pool)
{
foreach (var c in obj._components)
{
if (c.isActiveAndEnabled) c.SynchronizedUpdate();
}
}
}
#endregion
#region Fields
[SerializeField]
private int _order;
[SerializeField]
private bool _manageChildComponents;
[System.NonSerialized]
private IUpdateable[] _components;
#endregion
#region CONSTRUCTOR
private void OnEnable()
{
_components = _manageChildComponents ? this.GetComponentsInChildren<IUpdateable>(true) : this.GetComponents<IUpdateable>();
System.Array.Sort(_components, (a, b) => a.SubOrder.CompareTo(b.SubOrder));
Register(this);
TryStartCustomPlayerLoop();
}
private void OnDisable()
{
Unregister(this);
}
#endregion
#region Properties
public int Order
{
get => _order;
set
{
//if you want to support changing order while enabled & active, you'll need to sort the 'Pool' after doing this
if (this.isActiveAndEnabled) throw new System.InvalidOperationException("Modifying order while active is not supported.");
_order = value;
}
}
#endregion
#region Special Types
public interface IUpdateable
{
bool isActiveAndEnabled { get; } //as long as you inherit from MonoBehaviour this will automatically be implemented
int SubOrder { get => 0; } //the order of this script relative to the gameobject, default implementation in case you don't need it for that script
void SynchronizedUpdate();
}
#endregion
}
Example scripts:
public class zTest01 : MonoBehaviour, SynchronizedUpdater.IUpdateable
{
void SynchronizedUpdater.IUpdateable.SynchronizedUpdate()
{
//DO STUFF
}
}
public class zTest02 : MonoBehaviour, SynchronizedUpdater.IUpdateable
{
[SerializeField]
private int _suborder;
int SynchronizedUpdater.IUpdateable.SubOrder => _suborder;
void SynchronizedUpdater.IUpdateable.SynchronizedUpdate()
{
//DO STUFF
}
}
Note how I only define SubOrder for 1 of them. You may not require a ‘SubOrder’ for every script.
SubOrder in this scenario is the order of that script relative to other synchronized updateables on/in that gameobject.
…
NOTE - this is mostly untested slop code I slapped together real fast here in the forums just now. No guarantees it works perfectly and you may want to tweak to your needs. I left various comments through out highlighting certain aspects.
Or are there just a couple you want FIRST in the list, then you do any of the rest later.
I find in practice there’s often just a few criticals you gotta have in first, then the rest don’t matter, so it may be worth making a “early” and a “normal” list of delegates / registered objects just to keep it simple.
That way you don’t really need to keep thinking order for all future items, just “early or normal.”
You can also use a chain of dependencies build with singletons like this to ensure criticals are loaded in the order they must be:
(A → requests B → B → Requests C, etc. in a cascading explicit order of reference)
Some super-simple Singleton examples to take and modify:
Simple Unity3D Singleton (no predefined data):
Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:
These are pure-code solutions, DO NOT put anything into any scene, just access it via .Instance
Only cases were quick fixes using Script Execution Order, mainly when either the codebase was already spaghettized and it just needed to work, or when a third party script or some Unity API was involved and it was important that our code ran before or after that under all circumstances.
Hello everyone, thank you all for your answers and sorry for the late reply.
I’m not trying to guarantee the order so objects are instantiated in a way that dependencies are created first
I should have explained better: I don’t care about the order at all, I just want the order to be the same on every run, on every device.
That’s because I’m trying to achieve determinism.
I control the game loop call on each game object that’s being simulated, independently of Unity’s Update loop. For this, these game objects are registered to a manager, and most of the time the instantiation & subsequent registration are done through factories during the simulation so determinism is kept.
However, I do have a lot of game objects already in the scene, and these are currently being registered in their Awake methods. I could manually add them in edit time to the manager but I’d like a way to do it automatically.
Your best bet is to just take full control of all the magic methods. Your control script can have Awake, Start, etc while everything else has OnAwake, OnStart, etc that is called by the control script. I’m normally not a fan of this method but FindObjectsByType with LINQ may make sense here.
var behaviorsToRegister = FindObjectsByType<MonoBehaviour>(FindObjectsSortMode.None)
.OfType<IRegister>()
.OrderBy(obj => obj.ID) // or whatever you use for order of execution
.ToArray();
That’s exactly my original question, what to use for order execution? I can’t rely on GameObject names or Instance IDs, is there anything I can rely on? I don’t want to setup ids manually.
You are probably going to have to introduce your own data point to sort them by, honestly. But you can use editor scripts to automate their generation/assignment.
In that case I would go for the in-editor registration of the in-scene placed objects. It doesn’t take more than listen for the appropriate gameobject change events to register/unregister these objects. Having these already registered will also speed up scene loading a bit.
Just call it from other gameobject for example lets say you have 2 object and 2 scrippt attach to it object a will have reference to object b’s script and on awake you call it just like function
objectBscript myScript
awake
{
myscript.CallTheObjectBFunction();
}
you can arrange the which function will be called first
Or you can make an entire other script which will act like an manager
you can call every function you want to call in awake in that script