I think just about everyone who first faces an order of execution error immediately tries to move the scripts around in the component list, so I’d say the intuitive thing would be to do that, but then have the script execution in the editor override it so that older users don’t have anything new to learn.
If you went by order on the gameObject you’d have to hand-check the order on every object. One monster might be attacking funny since, only for that one monster attackScript and moveScript are in the wrong order. Every time you made a new monster you’d have to check the script were in the correct order. If you wanted to swap the order of the attack and move scripts you’d need to change it in every monster prefab (and also check places your your code may create them).
I also suspect Unity may group scripts by type. One list of every monsterMove script which it works through every frame. Looking through the order in each gameObject each frame would be more awkward.
The only advantage your idea has is if you wanted scripts to run Move, Attack on some things, but Attack, Move on others. I can’t think of any time I’d want that. And even if I did, I could have some other object do it: if(type==0) { move(); attack(); } else { attack(); move(); }.
While you are not crazy, there are many downsides to something like this:
Major changes to the engine may be required in order for this new execution order to be guaranteed at runtime for all platforms.
If this was an editor-only feature (because changing the engine for Unity is usually a big Unity no-no), similar to that of children-order not being guaranteed between editor and runtime, this could cause even more problems for newbies.
Even if the Unity Engine supported the feature 100% safely and consistently, it would likely be considered bad practice (for a lot of reasons) and it would only act as a bandaid to Unity’s much larger execution-order problem.
The fact of the matter is that you pretty much should always be using a custom-updater if many per-script execution orders need to be guaranteed within a package, framework, or game. And until Unity decides to move the engine to C# (and ditch the magic Update methods), this will pretty much always be the case.
So to recap; no, you are not crazy. But no, it’s not going to happen.
I do think Unity’s official tutorials should emphasize the importance of when to use Awake and Start, because that’s really the key difference-maker in whether or not you’d get execution order conflicts.
It really doesn’t help that the default auto-generated MonoBehaviour script tells new users to “Use Start for initialization”, when it, more often than not, should be Awake instead. It’s just setting up new users to run into this script execution order conflict when they inevitably do something like this…
public class ScriptA : MonoBehaviour {
public Rigidbody body; //Assume this is not assigned in the inspector.
void Start() {
body = GetComponent<Rigidbody>();
}
}
public class ScriptB : MonoBehaviour {
ScriptA scriptA;
float scriptAMass;
void Start() {
scriptA = GetComponent<ScriptA>();
scriptAMass = scriptA.body.mass;
}
}
…Which has the potential for Unity to call ScriptB’s Start method before ScriptA’s, meaning ScriptA’s body reference is null at the time ScriptB tries to do something with it.
The key things to note about Awake and Start however are:
Both methods are called once at initialization-time in the script’s lifecycle.
Awake is always called before Start.
All Awake methods are guaranteed to be called before the first Start method for every script in the scene.
The above problem would be fixed by just changing ScriptA to assign it’s body field in Awake instead of Start:
public class ScriptA : MonoBehaviour {
public Rigidbody body; //Assume this is not assigned in the inspector.
void Awake() {
body = GetComponent<Rigidbody>();
}
}
public class ScriptB : MonoBehaviour {
ScriptA scriptA;
float scriptAMass;
void Start() {
scriptA = GetComponent<ScriptA>();
scriptAMass = scriptA.body.mass;
}
}
So in general, you should:
Use Awake to initialize a script’s own data.
Use Start to initialize data that depends on other scripts.
But this is really not mentioned anywhere in Unity’s official docs or tutorials.
With that kind of statement the next thing you’ll be asking us to do is write equations that magically do not need to adhere to the mathematical order-of-operations.
Trust me. Ignoring the necessity of execution-order will only bring pain. It is far better to embrace it as part of your design and ensure key behaviors (or all behaviors) follow a defined execution order.
I mean, how else would you achieve determinism if Machine A is not guaranteed to process the game’s logic in the exact same order as Machine B, C, or D?
,…Because of this, you should not rely on one GameObject’s Awake being called before or after another (for example, you should not assume that a reference set up by one GameObject’s Awake will be usable in another GameObject’s Awake). Instead, you should use Awake to set up references between scripts, and use Start, which is called after all Awake calls are finished, to pass any information back and forth…"
… Yes?
In all my posts I am referring about the high-level concept of the necessity of a defined, somewhat static execution order — not Unity’s implementation specifically. (However looking back I can understand the confusion when I used the word “behaviours”)
If you create your own updater, yes, you no longer need to worry about it updating relative to other monobehaviours as everything in the updater will update at the updater’s given monobehaviour Update().
I do not believe this is tight coupling. Tight Coupling is where Object A requires Object B in order for it to function.
Whatever the case, though — assuming we’re using Unity’s Script Execution Order, Object A and Object B do not need to even know about one another in order to execute in an defined, order manner.
Here we are talking about unity execution order. If your domain relies on it to work properly its fragile and will break and be a headache to maintain.
Well, if two conponents are dependant of each others execution order they are very much too tightly coupled.
Having objects be tightly coupled is precisely why the [RequireComponent] attribute exists. Because like it or not you will be tightly coupling some portion of your code in order to use the built-in components (eg rigidbodies).
I hadn’t realized that Unity’s Script Execution Order was what you were referring to in your original post. Apologies for the confusion.
I agree — generally speaking Unity’s Script Execution Order should only be used for ordering frameworks / packages / plugins relative to one another. Unity’s Script Execution Order is wholly unsuitable for ordering each and every single monobehaviour within a given project.
Just because you can use enterprise coding methodologies to create games doesn’t mean it’s efficient to do so.
In fact just about everything you recommend to those around you comes with some degree of slow down to the overall development process in addition to the performance overhead. For a large scale project it can make sense to take some of these approaches but for everything else they’re not a great way to do things.