{"id":102,"date":"2013-11-04T10:49:51","date_gmt":"2013-11-04T09:49:51","guid":{"rendered":"http:\/\/mczerwonka.pl\/dev\/?p=102"},"modified":"2022-05-07T19:07:17","modified_gmt":"2022-05-07T17:07:17","slug":"unity-gui-resolution-independence","status":"publish","type":"post","link":"http:\/\/mczerwonka.pl\/dev\/unity-gui-resolution-independence\/","title":{"rendered":"Unity GUI: resolution independence"},"content":{"rendered":"<p>When using Unity GUI, you usually want your UI to be resolution independent. And you never know what resolution the user will run your game with,\u00a0when building for desktop (or floating canvas webplayer).<\/p>\n<p>Unity GUI works on absolute screen pixel coordinates, where (0,0) is top left corner of the screen, and (Screen.width, Screen.height) is bottom right corner.<\/p>\n<p>First thing I do when working with Unity GUI is picking neutral resolution. I design my UI to be ideal for this resolution.\u00a0Let&#8217;s say my neutral resolution is 1024 x 768 and I have three GUI elements:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-csharp\" data-lang=\"C#\"><code>GUI.Box ( new Rect (0, 0, 1024, 768 ), \"full screen box\" ); \nGUI.Box ( new Rect ( 10, 10, 400, 400 ), \"top left box\" ); \nGUI.Box ( new Rect ( 1024 - 410, 768 - 410, 400, 400 ), \"bottom right box\");<\/code><\/pre>\n<\/div>\n<p class=\"brush:csharp\"><a href=\"http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.30.36.png\"><img loading=\"lazy\" class=\"size-medium wp-image-104 aligncenter\" src=\"http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.30.36-300x225.png\" alt=\"Screen Shot 2013-11-04 at 10.30.36\" width=\"300\" height=\"225\" srcset=\"http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.30.36-300x225.png 300w, http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.30.36-1024x770.png 1024w, http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.30.36.png 1036w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p class=\"brush:csharp\">It looks as I expected, as soon as my game runs in 1024 x 768, which was picked as neutral resolution.<\/p>\n<p class=\"brush:csharp\"><!--more--><\/p>\n<p class=\"brush:csharp\">When I \u00a0run this code in the editor, and won&#8217;t allow game window to maximize &#8211; my UI will not scale itself to fit the window. It will rather extend beyond the viewport, as you can see on the screen below.<\/p>\n<p class=\"brush:csharp\"><a href=\"http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.32.00.png\"><img loading=\"lazy\" class=\"size-medium wp-image-105 aligncenter\" src=\"http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.32.00-300x235.png\" alt=\"Screen Shot 2013-11-04 at 10.32.00\" width=\"300\" height=\"235\" srcset=\"http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.32.00-300x235.png 300w, http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.32.00.png 766w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p class=\"brush:csharp\">There are two (well maybe more, but I will focus on two) ways to make this code resolution independent: docking and scaling. Each of them has its advantages, and disadvantages which depend mostly on the effect you try to achieve. Main differences between them is: do we fix positions, or do we fix sizes?<\/p>\n<p class=\"brush:csharp\">I will use game window as test environment for these two methods.<\/p>\n<h2 class=\"brush:csharp\"><\/h2>\n<h2 class=\"brush:csharp\">Docking<\/h2>\n<p class=\"brush:csharp\">What would happen, if I changed hardcoded constants 1024 and 764 to Screen.width, and Screen.height accordingly? Let&#8217;s see:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-csharp\" data-lang=\"C#\"><code>float width = Screen.width; \nfloat height = Screen.height;\nGUI.Box ( new Rect (0, 0, width, height ), \"full screen box\" ); \nGUI.Box ( new Rect ( 10, 10, 400, 400 ), \"top left box\" ); \nGUI.Box ( new Rect ( width - 410, height - 410, 400, 400 ), \"bottom right box\");<\/code><\/pre>\n<\/div>\n<p class=\"brush:csharp\"><a href=\"http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.42.48.png\"><img loading=\"lazy\" class=\"size-medium wp-image-106 aligncenter\" src=\"http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.42.48-300x232.png\" alt=\"Screen Shot 2013-11-04 at 10.42.48\" width=\"300\" height=\"232\" srcset=\"http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.42.48-300x232.png 300w, http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.42.48.png 759w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p class=\"brush:csharp\">The positions of elements are not absolute anymore, but relative to screen edges and this relation is fixed. In other words &#8211; positions are always relative to screen edgesa and this relation does not change with resolution change. I call this method docking, because it &#8220;docks&#8221; x and y coordinates of each control with one of screen edges (x with left or right, y with top or bottom).<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-csharp\" data-lang=\"C#\"><code>\/\/ docked to left and top edge of the screen \nGUI.Box ( new Rect ( 10, 10, 400, 400 ), \"top left box\" ); \n\/\/ docked to right and bottom edge of the screen \nGUI.Box ( new Rect ( width - 410, height - 410, 400, 400 ), \"bottom right box\");<\/code><\/pre>\n<\/div>\n<p class=\"brush:csharp\">Other thing we can see is, that the boxes now occupy most of the screen and top-left box overlap the text of the background box.<\/p>\n<p class=\"brush:csharp\">This drawback results from the fact, that box areas did not change, when we changed resolution. This is great advantage if you want your UI to be pixel perfect, but becomes problematic when you have big controls and need to switch to lower resolution (like in our scenario).<\/p>\n<h2 class=\"brush:csharp\">Scaling<\/h2>\n<p class=\"brush:csharp\">When using scaling, boxes positions change when changing resolution, but relative area of boxes\u00a0remain the same (they occupy the same percentage of area they did before resolution change). Example of scaling code:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-csharp\" data-lang=\"C#\"><code>float xFactor = Screen.width \/ 1024f; \nfloat yFactor = Screen.height \/ 768f; \nGUIUtility.ScaleAroundPivot( new Vector2 (xFactor, yFactor), Vector2.zero); \nGUI.Box ( new Rect (0, 0, 1024, 768 ), \"full screen box\" ); \nGUI.Box ( new Rect ( 10, 10, 400, 400 ), \"top left box\" ); \nGUI.Box ( new Rect ( 1024 - 410, 768 - 410, 400, 400 ), \"bottom right box\");<\/code><\/pre>\n<\/div>\n<p class=\"brush:csharp\">Function GUIUtility.ScaleAroundPivot changes GUI transformation matrix, so that each GUI control drawn below it will be scaled by the values of Vector2 we passed to it.<\/p>\n<p class=\"brush:csharp\"><a href=\"http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.45.59.png\"><img loading=\"lazy\" class=\"size-medium wp-image-107 aligncenter\" src=\"http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.45.59-300x236.png\" alt=\"Screen Shot 2013-11-04 at 10.45.59\" width=\"300\" height=\"236\" srcset=\"http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.45.59-300x236.png 300w, http:\/\/mczerwonka.pl\/dev\/wp-content\/uploads\/2013\/11\/Screen-Shot-2013-11-04-at-10.45.59.png 755w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p class=\"brush:csharp\">As you can see, I didn&#8217;t have to change UI drawing code at all &#8211; which is a big plus of scaling, when you have lots of controls which positions depend on each other. But also, there is a drawback. You can forget about pixel perfect when scaling the UI, as absolutely everything will be scaled up\/down to maintain the relative size of neutral resolution.<\/p>\n<p class=\"brush:csharp\">Each of these methods can be expanded for actual needs (ie. docking with size modifications, scaling with UI centered etc.), but this is out of the scope of this post.\u00a0To sup up &#8211; I use docking whenever I need my UI to be pixel perfect. But whenever I do not, or I want to have scaleable UI in the editor &#8211; I pick scaling.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When using Unity GUI, you usually want your UI to be resolution independent. And you never know what resolution the user will run your game with,\u00a0when building for desktop (or floating canvas webplayer). Unity GUI works on absolute screen pixel coordinates, where (0,0) is top left corner of the screen, and (Screen.width, Screen.height) is bottom right corner. First thing I do when working with Unity GUI is picking neutral resolution. I design my UI to be ideal for this resolution.\u00a0Let&#8217;s say my neutral resolution is 1024 x 768 and I have three GUI elements: GUI.Box ( new Rect (0, 0,\u2026<\/p>\n","protected":false},"author":1,"featured_media":106,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[4,9,10,11,12],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":5}},"_links":{"self":[{"href":"http:\/\/mczerwonka.pl\/dev\/wp-json\/wp\/v2\/posts\/102"}],"collection":[{"href":"http:\/\/mczerwonka.pl\/dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/mczerwonka.pl\/dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/mczerwonka.pl\/dev\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/mczerwonka.pl\/dev\/wp-json\/wp\/v2\/comments?post=102"}],"version-history":[{"count":13,"href":"http:\/\/mczerwonka.pl\/dev\/wp-json\/wp\/v2\/posts\/102\/revisions"}],"predecessor-version":[{"id":141,"href":"http:\/\/mczerwonka.pl\/dev\/wp-json\/wp\/v2\/posts\/102\/revisions\/141"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/mczerwonka.pl\/dev\/wp-json\/wp\/v2\/media\/106"}],"wp:attachment":[{"href":"http:\/\/mczerwonka.pl\/dev\/wp-json\/wp\/v2\/media?parent=102"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/mczerwonka.pl\/dev\/wp-json\/wp\/v2\/categories?post=102"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/mczerwonka.pl\/dev\/wp-json\/wp\/v2\/tags?post=102"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}