{"id":3518,"date":"2015-03-15T16:00:22","date_gmt":"2015-03-15T15:00:22","guid":{"rendered":"http:\/\/t-machine.org\/?p=3518"},"modified":"2015-03-15T17:11:15","modified_gmt":"2015-03-15T16:11:15","slug":"some-thoughts-on-loading-scenes-in-unity3d","status":"publish","type":"post","link":"http:\/\/new.t-machine.org\/index.php\/2015\/03\/15\/some-thoughts-on-loading-scenes-in-unity3d\/","title":{"rendered":"Some thoughts on loading Scenes in #unity3d"},"content":{"rendered":"<p>How do you program a &#8220;level&#8221;?<\/p>\n<p>This is not usually a problem in a\u00a0game engine, but Unity requires you to isolate each &#8220;level&#8221; as a Scene. And Unity&#8217;s Scenes have some strange design choices (bugs?) &#8211; IMHO they were designed for toy projects, not for production games.<\/p>\n<p>Here&#8217;s a stream-of-consciousness on what works, what doesn&#8217;t, and how I can workaround \/ do it better within Unity&#8230; it&#8217;s not carefully researched, mostly it&#8217;s from memory \/ off the top of my head. So &#8230; it might not all be true :).<\/p>\n<p>When I switch to Unreal4, I&#8217;ll be using posts like this as a baseline to compare where Unity failed, and how badly &#8211; or vice versa.<\/p>\n<p>UPDATE: added some more approaches and ideas\/commentary<\/p>\n<p><!--more--><\/p>\n<p>For example:<\/p>\n<ol>\n<li>When you load a Scene, everything in your game is destroyed\n<li>Scenes cannot take parameters\n<li>Scenes cannot hold state\n<li>Scenes cannot be constructed &#8211; nor modified &#8211; in code. Procedural game? HA! No chance!\n<li>You can&#8217;t edit more than one Scene at once (this is absurd, and makes development unnecessarily painful)\n<li> &#8230; and a bunch of other problems, many of which are side-effects of those above\n<\/ol>\n<h2>More Unity bugs that make this Hellish<\/h2>\n<ol>\n<li>When a Scene loads, there is <em>no way to tell Unity what code to run<\/em>.\n<ul>\n<li>This is REQUIRED because Unity refuses to let you pass parameters\n<li>Without it, you have to rely upon Awake(), Start(), and OnEnable()\n<li>Those three methods are DEFINED as running in &#8220;random&#8221; order among your objects\n<li>If you have a parameter that needs to be found, loaded, and positioned, you can put it in Awake()\n<li>If you need a global reference to that parameter, you&#8217;ll have to set it during Start(), otherwise there&#8217;s no guarantee it&#8217;s been found yet\n<li>Any code that needs to use that parameter cannot go in anything except OnEnable()\n<li>&#8230;BUT: a lot of (most?) Unity code that should be in Start() <em>will break<\/em> if it&#8217;s in OnEnable(). The two methods do different things!\n<\/ul>\n<\/ol>\n<p>Unity&#8217;s scene-loading SUCKS.<\/p>\n<h2>Some common workarounds<\/h2>\n<h3>Unity5: additive loading<\/h3>\n<p>You can load one Scene, and then load another over-the-top. This has long existed in Unity Pro to some extent (allowing &#8220;level loader&#8221; Scenes etc), but U5 upgrades\/extends it a bit.<\/p>\n<p>As I understand it, Unity5 does NOT fix the problems, but it does mitigate them. In particular, I&#8217;ve looked at Editor changes to improve handling for loading multiple scenes at once. I haven&#8217;t  experimented with this yet myself (I&#8217;m still on U4). From the videos I&#8217;ve seen, it looks like a definite improvement, but still quite a long way behind what I&#8217;d call &#8220;standard&#8221; in game-engines.<\/p>\n<p>If you&#8217;re able to use U5, I&#8217;d start with this, and see how far you can get with it. And then post \/ tweet about your tips and tricks, please.<\/p>\n<h3>Don&#8217;t Destroy On Load<\/h3>\n<p>You can mark any number of GameObjects as &#8220;Hey, Unity! When you delete everything (which is stupid, but OK), don&#8217;t delete THIS one!&#8221;<\/p>\n<p>In theory, that means you can write your own mini game-engine (um, why are you using Unity again? Because you want to re-invent the wheel all the time, right? \/sarcasm) that stores all the game-data in a &#8220;don&#8217;t destroy&#8221; object, and then parses and loads it after the new Scene has finished loading.<\/p>\n<p>This doesn&#8217;t solve anything &#8211; it shifts the problems to a new place, but at least they&#8217;re now in YOUR code, instead of in Unity&#8217;s. You end up writing your own mini game-engine. You get almost zero help from Unity, and &#8230; to make it harder &#8230; you have to remain compatible with Unity&#8217;s proprietary data-handing: Initialization protocols, crappy Serialization, etc.<\/p>\n<h3>Static variables<\/h3>\n<p>This is the &#8220;real&#8221; way of doing DontDestroyOnLoad, the standard approach that is built-in to the programming language. It always struck me as bizarre that Unity added DontDestroyOnLoad when there&#8217;s a more standard approach already in place. Was it a junior programmer who didn&#8217;t know how to use the &#8220;static&#8221; keyword? Or is there something nasty buried in Unity&#8217;s core engine that breaks on statics? (hint: I can almost guarantee it would be a bug somewhere in the Serialization system, which I detest, in case you hadn&#8217;t noticed already ;). Almost everything nasty in Unity&#8217;s architecture comes back to that monster!)<\/p>\n<p>It has always seemed to work fine for me. But it&#8217;s scary: when will it stop working? How will you know? What Unity bugs are lurking here?<\/p>\n<h3>Self-constructing Scenes<\/h3>\n<p>Take all the game-logic that WOULD have handed data to your Scene as parameters (in any normal engine) &#8230; and embed that INSIDE the Scene, instead.<\/p>\n<p>When the Scene loads, it runs this logic, and goes &#8220;Oh! I seem to be missing lots of core data. I&#8217;d better recreate it on the fly!&#8221;.<\/p>\n<p>It&#8217;s a tortuous kind of logic, and it can be very confusing for new devs joining your team (and for yourself, if you take a break from the project and return later). But it has some significant benefits:<\/p>\n<ul>\n<li>You can run a Scene in-game &#8230; OR &#8230; run it directly from Unity Editor, and it will behave (almost) identically. Testing + Debugging can be a lot quicker this way\n<li>Scenes remain self-contained. This is how Unity&#8217;s designers &#8220;intended&#8221; you to use Scenes (although it&#8217;s a really bad solution for Games). This has minor benefits with things all the way through to source-control and multi-user editing of your game: if you work this way, you&#8217;ll encounter slightly fewer of Unity&#8217;s core bugs.\n<li>In theory: more of the &#8220;Scene specific&#8221; code is located within the Scene (in Unity Editor). When your project gets large, in theory: this makes it easier to understand what&#8217;s going on, because the code + objects are local to each other. I&#8217;m not entirely convinced by this: with Unity&#8217;s poor arrangement of Code + Data &#8230; In practice, this locality might not be noticeable(the Unity Editor &#8220;hides&#8221; the locality, so you as developer get little benefit).\n<\/ul>\n<h3>Use Prefabs<\/h3>\n<p>Well, I&#8217;ve met people who claim to do it this way &#8211; make your Scene in Editor, then convert everything to Prefabs, then load the Prefabs when Scene loads, passing in a different list of &#8220;names of prefabs to load&#8221;.<\/p>\n<p>Oh man, please, no!<\/p>\n<p>Firstly: Prefabs in Unity are badly broken for anything complex like this. They don&#8217;t work, you should be avoiding them as much as possible &#8211; except for the simplest of use cases (non-nested, simple, small prefabs).<\/p>\n<p>Secondly: wow, this is tortuous. You&#8217;re abusing the &#8220;templated object system&#8221; to get around design-bugs in the &#8220;data layer&#8221; and &#8220;scene-loader&#8221;. It may be genius &#8211; but it&#8217;s the kind of genius that&#8217;s so unusual it&#8217;s prone to get broken in a future update to the engine, and Unity could legitimately say: &#8220;Wat? Why were you even doing that?&#8221;.<\/p>\n<p>If it works for you, great! But for me, this was always a mind-**** too far. Possibly I&#8217;m missing out, and this is a much better route than I realised. Mostly, it&#8217;s the fact that Unity can&#8217;t handle Prefabs that puts me off. U5 allegedly fixes some prefab bugs, so &#8230; I&#8217;ll re-consider this at some point. However, the history of Prefabs in Unity is ugly, and I&#8217;ll be very cautious about trusting them.<\/p>\n<h2>Problems with these workarounds<\/h2>\n<h3>Unity doesn&#8217;t support Dictionary\/Hashtable<\/h3>\n<p>This is an enormous stinking problem (throughout Unity!).<\/p>\n<p>It changes the balance of pros\/cons in the above workarounds. You cannot simply add named parameters to your static \/ DontDestroyOnLoad \/ etc &#8211; because Unity will piss all over the programming language and delete\/destroy\/corrupt them.<\/p>\n<p>(did I say I hate Unity&#8217;s broken-from-day-1 Serialization system yet? Yeah, well: I do)<\/p>\n<p>In the end, I&#8217;ve found that the most attractive part of DontDestroyOnLoad is that you can use:<\/p>\n<p>[csharp]<br \/>\nGameObject param1 = &#8230; ;<br \/>\nGameObject persistentObject = &#8230; ;<\/p>\n<p>param1.transform.parent = persistentObject.transform;<\/p>\n<p>\/\/param1.tag = &#8230; oh, no &#8211; can&#8217;t do this. Unity&#8217;s tags are hardcoded (that is NOT what Tag means, guys!)<\/p>\n<p>param1.name = &quot;Parameter 1&quot;;<br \/>\n[\/csharp]<\/p>\n<p>You can then retrieve it later using something like:<\/p>\n<p>[csharp]<br \/>\nGameObject persistentObject = &#8230; ;<br \/>\nGameObject param1 = persistentObject.Find( &quot;Parameter 1&quot; );<br \/>\n[\/csharp]<\/p>\n<p>(assuming you get a reference to the persistent object somehow &#8230; e.g. make it a Singleton)<\/p>\n<p>I believe you can do this with static objects too (?) but &#8230; having a whole object graph hiding in a static member variable is getting into the realm of &#8220;this will probably expose bugs in Unity Serialization&#8221;. Best to avoid it: life is too short to debug Unity.<\/p>\n<h2>Ideal \/ Correct solutions<\/h2>\n<h3>Data is Data<\/h2>\n<p>We come back to the recurring flaw in Unity that undermines so much of the engine: Unity refuses to acknowledge that &#8220;data&#8221; is &#8220;data&#8221;. It keeps insisting: &#8220;No, no! Data is code and objects and graphics and a physics object and &#8230; and &#8230; and &#8230; and &#8230;&#8221;.<\/p>\n<p>(Let&#8217;s be clear: experienced programmers look down on Unity&#8217;s approach and are generally scathing. This isn&#8217;t fanboism &#8211; the Unity approach to programming largely died in the 1980s, for good reasons. It&#8217;s unhelpfully restrictive, and quickly proved very difficult to create complex programs. e.g. Video Games)<\/p>\n<p>Ideally, we would store our game&#8217;s Data as data, and hand that data to the Scene when it loads. Unity blocks us from doing that. Everything we do to emulate this (e.g. embedding a JSON (de-)serializer) is a workaround for Unity&#8217;s road-blocks.<\/p>\n<h2>Current experiment<\/h2>\n<p>I&#8217;ve tried most of the above approaches with previous Unity projects, and none have worked out particularly well.<\/p>\n<p>What to try this time?<\/p>\n<p>Here&#8217;s my current needs:<\/p>\n<ol>\n<li>When the Scene loads, I need to inject the player-character. This is a complex object including rendering, physics, procedural meshes\n<li>When the Scene loads, I need to separately configure some invisible state: the player&#8217;s characteristics (e.g. Hitpoints, Score) &#8230; which the level clones, and uses as visible state (hitpoints during the level change; hitpoints when you started the level is a &#8220;saved&#8221; value that doesn&#8217;t change)\n<li>When the Scene loads, &#8230; I also have invisible state that is used to generate other state. e.g. information about how much of the level has been explored to date. Fog-of-war, etc.\n<li>When the player finishes the level, I need to cherry-pick some data to save out to the main menu, and to save to disk\n<li>When the player finishes the level, I need to store the differences between &#8220;before&#8221; and &#8220;after&#8221;, so that I can award various Badges\/Achievements, and one-time rewards, etc. Also: so that I can render &#8220;this is what you achieved!&#8221; end-screen\n<\/ol>\n<h3>Approach<\/h3>\n<p>I&#8217;ve given up: I&#8217;m writing my own mini-engine to workaround Unity&#8217;s awful scene-management. Looking back over my many Unity projects, I&#8217;ve lost many days, probably more than a week, on having to constantly re-implement this core feature because Unity&#8217;s version is so FUBAR.<\/p>\n<p>It&#8217;s one of those bugs that makes me think Unity&#8217;s tech leadership never write games themselves; if they did, they&#8217;d refuse to put up with crud like this.<\/p>\n<p>Short story:<\/p>\n<ul>\n<li>Write a class-load hook (using C#) to jump in every time a Scene starts loading\n<li>Debug all the undocumented crap that Unity does when loading a Scene. This could take a long time.\n<li>Reverse engineer what parts of a Unity scene are &#8220;Valid&#8221; and when.\n<li>Write the kind of code that every commercial game engine (except Unity!) has for managing scene-loading\n<li>Wrap it up in an API\n<li>&#8230;\n<li>Never deal with this turd that is Unity&#8217;s scene system ever, ever again!\n<\/ul>\n<h3>Useful features<\/h3>\n<h4>&#8220;Diff&#8221; two GameObjects<\/h4>\n<p>This would be fantastically useful. It would make many of the workarounds above much easier<\/p>\n<p>It also exists, built-in to Unity. We know this: the Serialization system relies upon it.<\/p>\n<p>But they don&#8217;t allow us access (as far as I can tell: I&#8217;ve not seen a public API call \/ set of calls for this?)<\/p>\n<h4>&#8220;Clone&#8221; a GameObject, keeping a reference to the original<\/h4>\n<p>All Objects in an OOP language (C# included) keep track of the Class that created them.<\/p>\n<p>If Unity would do the same thing with &#8220;clone object1 to create object2&#8221; &#8230; again, that would make many of the above approaches easier and less error-prone.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>How do you program a &#8220;level&#8221;? This is not usually a problem in a\u00a0game engine, but Unity requires you to isolate each &#8220;level&#8221; as a Scene. And Unity&#8217;s Scenes have some strange design choices (bugs?) &#8211; IMHO they were designed for toy projects, not for production games. Here&#8217;s a stream-of-consciousness on what works, what doesn&#8217;t, [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20,67],"tags":[],"_links":{"self":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/3518"}],"collection":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/comments?post=3518"}],"version-history":[{"count":4,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/3518\/revisions"}],"predecessor-version":[{"id":3522,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/3518\/revisions\/3522"}],"wp:attachment":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/media?parent=3518"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/categories?post=3518"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/tags?post=3518"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}