4 ms·
I found that the programming model in unity makes avoiding race conditions more inconvenient than in other types of programming. Specifically the component and
by gentleman11 6y ago
I found that the programming model in unity makes avoiding race conditions more inconvenient than in other types of programming. Specifically the component and game object initialization orders are not specified unless you do extra work to manually initialize everything in some clunky init code
- jayd16 6y agoA good pattern for this is to use the Unity serialization to inject all the references and initialized values you need. This allows Unity track all the dependencies and load everything you need. Unity is still crap at loading things in order but you simply have to make peace with that. Instead you have to write a bit more defensively and assume that your code will get initialized in a random order. As long as you use Unity serialization all the references will be set when the lifecycle callbacks fire. You can - Use coroutine Starts to wait for initialization - Ensure all the inits are done in Awake so things are ready during Start - You can also move away form initialization towards a more lazy pattern and make sure any calls into your behavior are asynchronous and include self init when needed. It is a bit clunky but you can get used to it. Lean into the idea of behaviors being asynchronous actors and it makes a bit more sense.
- dleslie 6y agoCoroutines are dangerous to use for initialization and I strongly recommend to be wary of that. All coroutines on a gameobject are halted if it is disabled, _and do not restart_ when it is re-enabled. For this reason it is easy to mistakenly leave a game object half-initialized, due to an enormous amount of plausible situations where some event, script or other may disable the game object. Now, there is a work-around: have Start yield a coroutine started on a "safe" object that will never disable. The caveat is that the caller can be destroyed during execution of the coroutine but the coroutine will persist to execute because it is on another object.
- jayd16 6y agoYou've just shifted the problem. Its better to just track your exact state and leverage the fact that you get exclusive atomic control of the main thread until you yield or return. The only lifecycle a behavior can trust is its own. Relying on other objects turns into a mess when your weak assumptions are violated. Besides causing a spaghetti mess of lifecycle tracking and callbacks and such, it leaves you wide open to the major problem if callbacks running pass the life of the thing to call back to. You've thrown away Unity's lifecycle tools by dumping everything into a big pot. Now you have to null-check in the callbacks to make sure your things are still alive. Track your own state and you'll be fine. Coroutines will stop when the owner dies and that is by design. Leverage that to ensure brain dead clean up. Objects are very often going to be disabled through user action anyway, eg quitting a level. Its better to just assume that will happen at any time and plan accordingly.
- dleslie 6y agoIn the case of UGC, you have zero ability to assume control of the object's lifecycle and enabled state. Zarro.