{"id":3529,"date":"2015-03-28T16:35:43","date_gmt":"2015-03-28T15:35:43","guid":{"rendered":"http:\/\/t-machine.org\/?p=3529"},"modified":"2015-03-28T16:46:16","modified_gmt":"2015-03-28T15:46:16","slug":"unity3ds-missing-core-no-runtime-objects","status":"publish","type":"post","link":"http:\/\/new.t-machine.org\/index.php\/2015\/03\/28\/unity3ds-missing-core-no-runtime-objects\/","title":{"rendered":"#Unity3d&#8217;s missing core: No runtime objects"},"content":{"rendered":"<p>Here&#8217;s a game:<\/p>\n<ul>\n<li>Player\n<ul>\n<li>Inventory\n<ul>\n<li>Gun 1\n<ul>\n<li>AmmoHolder\n<\/ul>\n<li>Gun 2\n<ul>\n<li>AmmoHolder\n<\/ul>\n<\/ul>\n<\/ul>\n<\/ul>\n<p>Some of those are 3D visual objects: Player, Gun 1, Gun 2.<\/p>\n<p>Some of those are abstract concepts, or data: Inventory, AmmoHolder.<\/p>\n<p>(in a Diablo clone, the Inventory might be a visual object, but only when you bring up the popup-window to display it. By contrast, in a simple FPS, your inventory may not be displayed at all &#8211; no need for it!)<\/p>\n<p><strong>Unity cannot handle this situation.<\/strong><\/p>\n<h2>What you need<\/h2>\n<p>Classes:<\/p>\n<ul>\n<li>PlayerClass\n<li>InventoryClass\n<li>GunClass\n<li>AmmoHolderClass\n<\/ul>\n<p>In Unity, you have to make &#8220;everything&#8221; extend MonoBehaviour. That&#8217;s fine for PlayerClass and GunClass: you make a dummy GameObject for each, place it into the scene, and attach the class as a Component.<\/p>\n<p>But that&#8217;s impossible for InventoryClass and AmmoHolderClass: if you make them into MonoBehaviours, Unity prevents you from using them as standard classes any more:<\/p>\n<ol>\n<li>Cannot instantiate them\n<li>Cannot use Garbage Collection\n<\/ol>\n<p>&#8230;because they have no GameObject to be attached to &#8211; they don&#8217;t exist! They are abstractions only.<\/p>\n<p>This is core to programming: we use abstractions all the time. Without them, coding would be horrendously inefficient both for the programmer and (to a lesser extent) for the computer.<\/p>\n<h2>What Unity offers<\/h2>\n<p>You have three alternatives here:<\/p>\n<ol>\n<li>Create fake GameObjects anyway. Put them &#8220;somewhere&#8221;. Work really hard to make sure they never accidentally appear in front of the camera (!), or interact with the scene due to physics (!), etc\n<li>Use plain C# classes. <strong>This is an extremely bad idea:<\/strong> Unity has never supported C# classes for anything; Unity has a custom memory-management solution (called, slightly confusingly, &#8220;Serialization&#8221;) which is incompatible with plain C#. It requires every object to extend Unity.Object. You can workaround this; it requires major work and is very hard to get right.\n<li>Use ScriptableObject, which appears to have been invented for this. According to many Unity developers: &#8220;this is what ScriptableObject is for&#8221;. However, that&#8217;s wrong. Very wrong.\n<\/ol>\n<h3>ScriptableObject to the rescue?<\/h3>\n<p>So &#8230; ScriptableObject is something that extends UnityObject (fixing the problem of &#8220;plain C# classes aren&#8217;t compatible with Unity&#8221;), and you can use in a Scene, and can be referenced by MonoBehaviours, and just work, right?<\/p>\n<p>Wrong.<\/p>\n<p>ScriptableObject is all those things, except: it doesn&#8217;t exist in the Scene. It&#8217;s an Asset.<\/p>\n<p>This is where Unity docs really screw the pooch. We know for a fact that an SO is an Asset; when we try to use it like a MonoBehaviour, several things break and stop working.<\/p>\n<p>&#8230;but it also &#8220;kind of&#8221; works in-Scene. The docs have no explanation for this. What are the limits? Well, basically: no-one knows, except through trial and error. This is so core to your code that it sometimes instead means:<\/p>\n<blockquote><p>\ntrial and oh-crap-that-didn&#8217;t-work-time-to-rewrite-every-damn-class\n<\/p><\/blockquote>\n<h4>Why is Asset-hood so bad?<\/h4>\n<p>You already have all that &#8211; it&#8217;s called the Class &#8211; and to have an Asset too simply creates problems:<\/p>\n<ul>\n<li>An Asset is a special thing in Unity. It interacts with Unity&#8217;s core systems in very different ways to a C# object. Building, runtime Loading, editing in the Editor &#8211; all are &#8220;different&#8221;.\n<li>You can&#8217;t create them in the Editor. (you can write your own hack\/script to fix this. It&#8217;s only 10 lines of code. But &#8230; yeah. It&#8217;s a hint that this isn&#8217;t what Assets are intended for)\n<\/ul>\n<h4>But .. what&#8217;s ScriptableObject for?<\/h4>\n<p>Unity&#8217;s official docs are rather &#8230; incoherent &#8230; on the subject. My guess is that they were written by someone who didn&#8217;t really understand ScriptableObject, and was looking at the source code thinking:<\/p>\n<blockquote><p>\nWTF is this? Um. Err. Well &#8230; it kind-of seems to sort-of do &#8230; this? Maybe?\n<\/p><\/blockquote>\n<p>&#8230;and worked it out from observation.<\/p>\n<p>What the docs are TRYING to say is:<\/p>\n<blockquote><p>\n(gross over-simplification here to make things easy to understand): Unity&#8217;s memory-management COPIES every instance many times, and doesn&#8217;t support pointers\/references.<\/p>\n<p>This is a HUGE problem in game-development.<\/p>\n<p>ScriptableObject is a workaround that uses diskspace to make templates out of objects, and then simulates pointers by using one shared-file on disk to hold the data for thousands of in-game objects.<\/p>\n<p><strong>This works very well, because the way we built Unity&#8217;s core architecture (3D Meshes, Textures etc) already supports that workflow: File-on-disk generates optimized in-memory-object, which is shared\/batched wherever possible.<\/strong>\n<\/p><\/blockquote>\n<p>Going off on a tangent, it waffles about &#8220;ShopStore&#8221; and &#8220;Multiple Scenes&#8221; and stuff that the author clearly didn&#8217;t really understand. The obvious way of implementing what&#8217;s described in the docs is many times simpler, and works much better &#8211; you would never do it using ScriptableObject.<\/p>\n<p>What the docs perhaps should have instead said was:<\/p>\n<blockquote><p>\nYou can also abuse this system to make hardcoded fake in-scene objects that don&#8217;t have to be attached to a GameObject.<\/p>\n<p>This will fail if you have any Procedural Content &#8211; but Unity was specifically designed never to be used in games that have procedural generation, and no-one should be doing procedural work in Unity, so that&#8217;s fine.<\/p>\n<p>Wait &#8230; what? What do you mean &#8220;we all do procedural generation&#8221;? Wh &#8230; why? Why would you do such a thing? <strong>do you have any idea how slow that will be in Unity? Most of our code assumes everything is done at compile time! We can&#8217;t handle dynamic code!!!<\/strong>\n<\/p><\/blockquote>\n<p>(NB: Unity used to be really, really bad at procedural work. Way too slow. There&#8217;s really no reason not to be doing tonnes of procedural code in Unity games today &#8211; except that Unity itself still has a load of political blocks on it. It doesn&#8217;t support procedural properly in places where it could)<\/p>\n<p>ScriptableObject is great, but most game-development works with procedural content. I&#8217;m not talking about complex cool stuff like <a href=\"http:\/\/www.big-robot.com\/tag\/sir-you-are-being-hunted\/\">Sir, you are being hunted<\/a>. I&#8217;m talking about stuff like:<\/p>\n<blockquote><p>\nThe set of objects in your inventory changes from moment to moment while you play the game. Because otherwise it would be a pretty boring game\n<\/p><\/blockquote>\n<p>When you try to use ScriptableOject here, you are abusing it. It&#8217;s not intended for that, it doesn&#8217;t work correctly with that, and it&#8217;ll make your life hard. IT&#8217;s not ScriptableObject&#8217;s fault; it&#8217;s your fault.<\/p>\n<h2>What does Unity need?<\/h2>\n<p>At a conceptual level, Unity has:<\/p>\n<ul>\n<li>&#8220;Physical Runtime objects&#8221;: things that have 3D physical presence in the editro (not Physics as in &#8220;Physics Engine&#8221;, but rather: everything has a Transform)\n<li>&#8220;Runtime OOP Objects, dependent upon GameObject&#8221;: generated from OOP Classes (but MUST be attached to a Physical Runtime object)\n<li>&#8220;Compile time OOP Objects&#8221;: these are Unity Assets, and can be used for some performance and coding tricks. They are they poorly-documented ScriptableObject, <strong>and should probably have been named ScriptableAsset in the first place<\/strong> since they are <em>absolutely not Objects!<\/em>\n<\/ul>\n<p>What&#8217;s missing?<\/p>\n<ul>\n<li>&#8220;Runtime OOP Objects, <strong>in<\/strong>dependent of GameObject: the classic &#8220;Object&#8221; from OOP.\n<\/ul>\n<p>I think &#8230; not sure, this seems obvious, but if so: why is not already the case? &#8230; I think: Unity should be saying &#8220;make your classes extend &#8216;Unity.Object&#8217;, and then use them. All will be fine. We&#8217;ve made it work under-the-hood; trust us, guys, it&#8217;s cool. Everything&#8217;s cool.&#8221;.<\/p>\n<p>My guess is that&#8217;s some internal bug with Unity Serialization that makes this untractable. Maybe something like:<\/p>\n<blockquote><p>\nGUESS: Unity Seriailization is internally hardcoded with a fixed number of recognized classes, somewhere, that can only be added to by hardcoding new ones. Because we don&#8217;t have access to Unity&#8217;s source code, we cannot re-generate those, and the Unity Editor (for same reason) can&#8217;t do it for us.<\/p>\n<p>So: our legitimate C# classes can never be fully treated as a Unity Class.<\/p>\n<p>Instead, Unity has to support a fixed number of hardcoded classes (O hai! ScriptableObject, MonoBehaviour), and those have to use reflection tricks at runtime to provide (limited) support for the infinitely many user-authored clases from C#.\n<\/p><\/blockquote>\n<p>OK, so this is slightly more than a &#8220;guess&#8221;. They have form here: When trying to figure out some obscure Unity Serialization bugs, I found some places where Unity would load extra, hidden, information for particular Unity classes. There was nothing in memory on this, suggesting that they had hardcoded a lookup for their set of &#8220;known&#8221; Unity classes, and were getting the data that way.<\/p>\n<p>&#8230;but that&#8217;s the kind of thing that&#8217;s going to be a genuine mind-f*ck to try and unravel. This makes me inclined towards it: even with the money and resource Unity has, it would be non-trivial to fix. And I&#8217;m pretty sure no-one likes the status quo.<\/p>\n<h2>Conclusions<\/h2>\n<p>We&#8217;ll just keep writing source code like it&#8217;s 1999:<\/p>\n<ul>\n<li>Use C# as if it&#8217;s C\n<li>F*ck Garbage Collection (we can&#8217;t have it :( Sob.)\n<li>Manually memory-manage the scene and objects; make everything a GameObject, and manually Destroy() everything each time you replace it or it goes out of scope\n<li>&#8230;\n<li>As a bonus: the Unity Editor has much better support for Developing and Debugging games which use GameObjects than it does for any alternatives (C# Classes; ScriptableObjects)\n<\/ul>\n<p>I&#8217;m crossing my fingers that Unity version 6 will dump Serialization, and this problem will go away. Like magic, Unity will fully support C# (Dictionary&#8217;s! Objects! Garbage Collection! YAY!)<\/p>\n<p>&#8230;of course, by then, I might have finally switched to Unreal. Because frankly I&#8217;ve got better things to do with my life than work in low-level programming languages!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here&#8217;s a game: Player Inventory Gun 1 AmmoHolder Gun 2 AmmoHolder Some of those are 3D visual objects: Player, Gun 1, Gun 2. Some of those are abstract concepts, or data: Inventory, AmmoHolder. (in a Diablo clone, the Inventory might be a visual object, but only when you bring up the popup-window to display it. [&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\/3529"}],"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=3529"}],"version-history":[{"count":6,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/3529\/revisions"}],"predecessor-version":[{"id":3535,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/3529\/revisions\/3535"}],"wp:attachment":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/media?parent=3529"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/categories?post=3529"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/tags?post=3529"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}