5 ms·
The most important thing about Unity is to know that the Editor is not the same as the Client. Assets load differently, in surprising ways. Materials may work
by dleslie 6y ago
The most important thing about Unity is to know that the Editor is not the same as the Client.
Assets load differently, in surprising ways. Materials may work fine in Editor but not in Client.
Code executes differently. Timings are different, the Editor shares managed Heap with the Client, and so garbage collection is different.
And so on.
Rule 0 with Unity: _do not rely on the Editor for testing_.
- cmeacham98 6y agoHot take: to some extent, this is a good thing as it discourages relying on emergent behavior in the client, like timings, the heap, etc that may or may not differ between your machine, your player's machines, and even future hardware that does not exist right now.
- Eyas 6y agoI'm with you there, but (and, this is an unpopular opinion) I think it would be even better if it went the way of Go. Go will randomize iteration order of unordered collections (at least in development builds?) on purpose so you learn not depend on it. The "tricky" thing with Unity is that you might find a consistent client behavior and unknowingly depend on it. I think with time/experience you'll learn to spot what to ignore (frame lengths, etc) and what you could count on. And just to test fully-build games often, and across clients. * C# does something similar with hash across builds (so you don't depend on serializing/deserializing hashes and expect them to work; they want the freedom to change hash functions).
- conradludgate 6y agoGo doesn't randomise map order, it's just indeterminate. It picks a lot random bucket to start the iteration but the order will always be the same in the end (at least when I last investigated it). It's essentially free, so it does it in production too
- jayd16 6y agoDon't rely on race conditions and your code will run similarly on device and in editor. I agree that you can't easily use editor performance profiles though; there's far too much editor noise.
- gentleman11 6y agoI 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.