{"id":1206,"date":"2014-10-25T08:50:01","date_gmt":"2014-10-25T07:50:01","guid":{"rendered":"http:\/\/www.aymericlamboley.fr\/blog\/?p=1206"},"modified":"2014-11-28T17:48:36","modified_gmt":"2014-11-28T16:48:36","slug":"unity2d-the-good-the-bad-and-the-ugly","status":"publish","type":"post","link":"http:\/\/www.aymericlamboley.fr\/blog\/unity2d-the-good-the-bad-and-the-ugly\/","title":{"rendered":"Unity2D the Good, the Bad and the Ugly."},"content":{"rendered":"<p>Hey guys, after more than one year working with Unity, I thought it was time to give some feedbacks. With Tamsen (aka Gsynuh) we worked on a 3D game which has been canceled unfortunately. Anyway we were really happy to use Unity3D for this project instead of using <a href=\"http:\/\/away3d.com\/\" target=\"_blank\">Away3D<\/a> (we&#8217;re mostly AS3 developers).<\/p>\n<p>Now Tamsen is working full time on <a href=\"http:\/\/www.ulule.com\/a-blind-legend\/\" target=\"_blank\">A Blind Legend<\/a> (we will provide you soon a blog report on this exciting project!), built with Unity3D. On my side I will help him on specific tasks, I&#8217;ve also several AS3 projects, and one game in progress using Unity2D.<\/p>\n<p>For those of you who don&#8217;t know me, I worked on the <a href=\"http:\/\/citrusengine.com\/\" target=\"_blank\">Citrus Engine<\/a> and so I&#8217;m very familiar with <a href=\"http:\/\/starling-framework.org\/\" target=\"_blank\">Starling<\/a> framework (a 2D API). This background precision is important to understand my approach of Unity2D.<\/p>\n<p><!--more--><\/p>\n<p><strong>The Good<\/strong><br \/>\nWe were really happy of <strong>Unity&#8217;s Editor<\/strong> (we all know its Unity strength) working on the 3D game, and I really enjoy to use it with Unity2D. If you&#8217;ve never worked with Unity2D have a look on this great <a href=\"http:\/\/unity3d.com\/learn\/tutorials\/modules\/beginner\/2d\/2d-overview\" target=\"_blank\">tutorial<\/a>. I have long dreamed of something similar for the Citrus Engine but it would require many days of work. So we have some custom cheap editors which do their job really great on big project, but they are missing lots of features. Basically when you make a small 2D game with Starling, you create \/ display \/ position everything via code.<\/p>\n<p>One of the key feature of Unity&#8217;s Editor is the ability to <strong>script Editor<\/strong> to create your own tool inside Unity. I didn&#8217;t try it myself, but Tamsen did and he loves it.<\/p>\n<p>With Unity 4.6, there is the <strong>new GUI<\/strong>. I started my Unity2D game project with <a href=\"https:\/\/www.assetstore.unity3d.com\/en\/#!\/content\/2413\" target=\"_blank\">NGUI<\/a> but dropped it as soon as I tested new Unity&#8217;s GUI! They made an excellent job, kudos guys. With Starling, we use <a href=\"http:\/\/feathersui.com\/\" target=\"_blank\">Feathers<\/a> for complex UI which works great but it&#8217;s a pain to add\/customize, and the api is complex. A big app made with Feathers will be out soon and of course they will be a new blog post. Using Unity new GUI it was really easy to built our custom UI and even a designer could manipulate it thanks to the Editor.<\/p>\n<p>Unity also comes with a really strong Vector math librarie. In AS3 I often used <a href=\"http:\/\/napephys.com\/\" target=\"_blank\">Nape<\/a> (even if don&#8217;t use the physics at all) just for having a strong Vector math library. In Unity2D you can do directly amazing things:<\/p>\n<pre lang=\"csharp\">while(Vector2.Distance(transform.pos1, pos2) > .01f)\r\n\ttransform.pos1 = vector2.MoveTowards(transform.pos1, pos2, speed * Time.delta)<\/pre>\n<p><strong>The Bad<\/strong><br \/>\nOk, so that was for the good things. Wait, what!? What about Unity2D itself? I think its overkill. Unity2D is base on Unity3D, and we&#8217;re still manipulating <strong>Vector3<\/strong> to move our objects.<\/p>\n<p>An other thing is <strong>coordinate manipulation<\/strong>. We&#8217;re often switching between <em>Camera.main.ScreenToWorldPoint<\/em> and <em>Camera.main.WorldToScreenPoint<\/em>. This kind of manipulation is classical in a 3D API but not all in a 2D one. In the following code, I put my stairs sprite in the bottom right corner. This is the crazy code:<\/p>\n<pre lang=\"csharp\">SpriteRenderer stairs = GameObject.Find(\"Level\/stairs\").GetComponent<SpriteRenderer>();\r\nstairs.transform.position = new Vector3(Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, 0, 0)).x - stairs.bounds.size.x \/ 2, -Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height, 0)).y + stairs.bounds.size.y \/ 2, 0);<\/pre>\n<p>It seems that Unity2D has the wind in its sails from the game developer community, but I wonder how they deal with some features. Let&#8217;s take a basic one : how to put a <strong>blur filter<\/strong> on a SpriteRender? I didn&#8217;t find a simple way, even after looking on the Unity Asset Store. My conclusion is that I&#8217;ve to write my own material with custom shader for the blur effect. And it would be the same for some other filters ColorMatrixFilter, DisplacementMapFilter&#8230; Are you serious, no one is using filter? Why are they not included by default, for a 3500\u20ac framework that&#8217;s a shame!?<\/p>\n<p>An other crazy thing is the impossibility to mask \/ clip 2D SpriteRenderer via Unity2D API. You will have to create your own shaders. <a href=\"http:\/\/forum.unity3d.com\/threads\/is-it-possible-to-clip-a-sprite-with-another-sprite.254144\/#post-1679940\" target=\"_blank\">This one<\/a> is working fine (except on Nexus 7 and probably the Ouya due to Tegra 3).<\/p>\n<p>An other thing which highlight the limit of Unity2D API is to work with <strong>TextureAtlas\/SpriteSheet<\/strong>. Unity2D support them, and they have a great tool named Sprite Packer which is very useful. Note that you may also use <a href=\"http:\/\/www.codeandweb.com\/texturepacker\" target=\"_blank\">TexturePacker<\/a>. So Unity may combine sprites into a SpriteSheet (with many options), that&#8217;s great. However <strong>you can&#8217;t access to those sprites via code<\/strong>. For accessing the sprite needed you have to define a public property in your code and give the sprite reference via the editor.<br \/>\nOr if you really want to do it via code (and often you will!) you have to put them in the Resources folder and load them at runtime:<\/p>\n<pre lang=\"csharp\">public List<Texture2D> spriteSheets; \/\/note that here you make the link via the editor\r\nprivate List<Sprite> _sprites = new List<Sprite>();\r\n\r\n\/\/loading texture in memory\r\nfor (int i = 0; i < spriteSheets.Count; ++i)\r\n\t_sprites.AddRange(Resources.LoadAll<Sprite>(\"world_three\/symbols\" + i).ToList<Sprite>());\r\n\r\n\/\/getting a Sprite\r\nstatic public Sprite GetSprite(List<Sprite> sprites, string name) {\r\n\t\r\n\tfor (int i = 0; i < sprites.Count; ++i) {\r\n\t\t\r\n\t\tif (sprites[i].name == name)\r\n\t\t\treturn sprites[i];\r\n\t}\r\n\t\r\n\treturn null;\r\n}<\/pre>\n<p>It isn't very programmer friendly, isn't it?<\/p>\n<p>An other strange thing is the layer system: <strong>Order in Layer<\/strong>. You will expect that two sprites can't have the same layer, but they can. So does the last object created will be on top or behind the previous one? It depends. Of what? No idea. Even if you move the object inside the Hierarchy, it doesn't change anything. Even worse, if you have a Sprite Render's child the order in layer doesn't refer to the parents one but to the global one! You can imagine easily the nightmare on complex game... Why on earth each object hasn't its own index and each children too according to their parents like in any display-list framework!?<\/p>\n<p><strong>The Ugly<\/strong><br \/>\nThere are bad things in Unity2D and there are also ugly things. It's very common in a 2D game to have a Sprite as a container and push children inside which may have children etc. And you probably want to position this container according to its size. Hard to believe but it isn't easy to do with Unity2D. <strong>2D Bounds parent doesn't consider children<\/strong>, you have to make your own <a href=\"http:\/\/stackoverflow.com\/questions\/11949463\/how-to-get-size-of-parent-game-object\/11960936#11960936\">function<\/a>:<\/p>\n<pre lang=\"csharp\">static public Bounds GetBounds(Transform parent) {\r\n\r\n\tVector3 center = Vector3.zero;\r\n\tforeach (Transform child in parent)\r\n\t\tcenter += child.gameObject.renderer.bounds.center;\r\n\t\r\n\tcenter \/= parent.childCount;\r\n\t\r\n\tBounds bounds = new Bounds(center,Vector3.zero);\r\n\t\r\n\tforeach (Transform child in parent)\r\n\t\tbounds.Encapsulate(child.gameObject.renderer.bounds);\r\n\r\n\treturn bounds;\r\n}<\/pre>\n<p>In a game it's very common to change <strong>Sprites's alpha<\/strong>. Using Unity2D you must go through the color class unless you did it via the Editor. And you can't change it directly, you have to change the whole color variable.<\/p>\n<pre lang=\"csharp\">Color tmpColor = myObject.GetComponent<SpriteRenderer>().color;\r\ntmpColor.a = 0;\r\nmyObject.GetComponent<SpriteRenderer>().color = tmpColor;<\/pre>\n<p>I know that many things (transform) work that way in Unity, but for small things like Color I can't get the reason.<\/p>\n<p>Working with Starling framework we have to <strong>manage SpriteSheets loading, maximum textures size<\/strong> (4096 x 4096 for an iPad retina, but 2048 x 2048 for an iPhone4S etc.), <strong>multi-resolution management<\/strong> (you won't load the 4096 x 4096 assets on an iPhone 3GS). When you start with Unity2D you think that everything is automatically managed under the hood... but it isn't. <strong>There is no magick here<\/strong>! In fact how does Unity manage the multi-resolution development? It doesn't. You have to handle it yourself via your code. At thirst I thought Unity2D was smart enough to override my texture size depending my mobile device but it doesn't. So how to manage assets between a 3GS and an iPad retina? Provide several resolutions but don't put them in the Textures directory or both will be loaded. Also if you use the Editor for putting Sprite into stage it won't handle the good SpriteSheet to use at runtime.<br \/>\nAlso I lost 2 hours because I forgot to override a Texture Size to 2048x2048 for my iPhone4S. Unity2D didn't gave me any error, just a crash on the device. And Xcode just told me: application received memory warning. <strong>It's critical that those points are not clearly detailed in an official Unity blog post.<\/strong><\/p>\n<p>Please, tell me that I'm wrong on many points and correct me. Using Starling I can handle everything and know what the engine is doing. For a small game, for sure I will stay on Starling. However for a big one, Unity2D is really attractive if you work closely with graphic designer (or game designer adjusting physics in real time!), but for coder the API is hell! Please report your issue to make Unity2D better.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey guys, after more than one year working with Unity, I thought it was time to give some feedbacks. With Tamsen (aka Gsynuh) we worked on a 3D game which has been canceled unfortunately. Anyway we were really happy to use Unity3D for this project instead of using Away3D (we&#8217;re mostly AS3 developers). Now Tamsen &hellip; <a href=\"http:\/\/www.aymericlamboley.fr\/blog\/unity2d-the-good-the-bad-and-the-ugly\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Unity2D the Good, the Bad and the Ugly.<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[164],"tags":[176],"_links":{"self":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/1206"}],"collection":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/comments?post=1206"}],"version-history":[{"count":23,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/1206\/revisions"}],"predecessor-version":[{"id":1334,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/1206\/revisions\/1334"}],"wp:attachment":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/media?parent=1206"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/categories?post=1206"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/tags?post=1206"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}