{"id":689,"date":"2017-12-23T10:21:11","date_gmt":"2017-12-23T10:21:11","guid":{"rendered":"http:\/\/www.netexl.com\/blog\/?p=689"},"modified":"2017-12-23T10:24:34","modified_gmt":"2017-12-23T10:24:34","slug":"making-of-a-responsive-mobile-game-app-using-phaser-calculation-for-game-size","status":"publish","type":"post","link":"https:\/\/www.netexl.com\/blog\/making-of-a-responsive-mobile-game-app-using-phaser-calculation-for-game-size\/","title":{"rendered":"Making of a Responsive Mobile Game App using Phaser: Calculation for Game Size"},"content":{"rendered":"<p>In my <a href=\"https:\/\/www.netexl.com\/blog\/making-of-a-responsive-mobile-game-app-using-phaser-introduction\/\" target=\"_blank\">introductory article<\/a> on this series I talked about using SHOW_ALL scale mode for my game which fits perfectly for need to be responsive. It will resize the game to fit into available space using the original aspect ratio which was used to develop the game. The only issue I saw was the &#8220;letter-boxing&#8221; effect so\u00a0if device&#8217;s aspect ratio was different than the game&#8217;s aspect ratio, there will be blank space around either horizontal edges or vertical edges.<\/p>\n<p>We can account for that extra available space when loading new game and positioning of all ui controls can then be done relative to available space which is similar to how we handled RESIZE scale mode. The only difference here is that it can only be done once in SHOW_ALL scale mode when the game is initialized. In mobile app this is not going to be a problem and we can optimize\u00a0our game for only one orientation and no resizing will occur once the game is loaded.<\/p>\n<p>Now let us jump onto deciding game resolutions. We need to take into account the available width on mobile\u00a0as well as pixel-density. In your HTML file make sure to include viewport meta tag which\u00a0can be used to control area in which game is shown. Most responsive amd mobile friendly web pages have following viewport definiton<\/p>\n<blockquote><p>\u00a0 &lt;meta name=&#8221;viewport&#8221; content=&#8221;width=device-width, minimum-scale=1, initial-scale=1, user-scalable=no&#8221;&gt;<\/p><\/blockquote>\n<p>Setting width to device-width ensures you get your device&#8217;s logical CSS width.<\/p>\n<p>Second factor to consider on mobile devices is\u00a0devicePixelRatio. This can be obtained by calling window.devicePixelRatio property. Mobile devices have more pixels than the logical CSS width. For desktops\u00a0devicePixelRatio is 1 but for mobile devices, it is normally greater than 1 so\u00a0we normally have more pixels available to draw our game\u00a0on mobile devices.<\/p>\n<p>We have two options here. We can ignore\u00a0devicePixelRatio and only consider the game size\u00a0according\u00a0to CSS width and height which means that we are creating games for lower resolutions and game may not look crispy enough which is fine for most of the games.<\/p>\n<p>The second option is to multiply\u00a0devicePixelRatio to CSS width and height to get actual pixel width and height and draw the game for actual pixel width and height and then resize the game to fit into the available space which will look better on high resolution devices (did I say retina display?).<\/p>\n<p>I am going to take\u00a0devicePixelRatio into account and make my game look more crispy at the cost of some performance hit which I have yet to measure how much? So we get device width and height and then multiply it with\u00a0devicePixelRatio and get pixel width and height and use that to initialize our game.<\/p>\n<p>We are also going to make the game according to the device aspect ratio and not the game&#8217;s aspect ratio which we used to\u00a0generate our assets.<\/p>\n<p>Let say we planned to create game assets for 960&#215;640 which has an aspect ratio of 1.5 so all assets will be made accordingly to fit into this area. Now if we get a device which has an aspect ratio of 1.6, then we have extra space around\u00a0vertical edges\u00a0so calculated new\u00a0width of\u00a0our game would be 960*1.6\/1.5 = 1024 and size of the game would be 1024&#215;640.<\/p>\n<p>If we have an aspect ratio of 1.4, then we\u00a0will have space around horizontal edges\u00a0and\u00a0game\u00a0height will be calculated to 640*1.5\/1.4 = 685 and game size would become 960&#215;685. You can see in our game we are just getting some extra space either on horizontal edges or vertical edges so game assets will have no issues being displayed in full. The only change which will happen would be their relative positioning which will change for different aspect ratios. In the diagram below the area highlighed in yellow is the extra space we get in our game which we are going to include in the game. The middle section (Game Area) is the planned game size<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-691 size-full\" src=\"https:\/\/www.netexl.com\/blog\/wp-content\/uploads\/2017\/12\/GameAspectRatio.png\" alt=\"\" width=\"761\" height=\"201\" srcset=\"https:\/\/www.netexl.com\/blog\/wp-content\/uploads\/2017\/12\/GameAspectRatio.png 761w, https:\/\/www.netexl.com\/blog\/wp-content\/uploads\/2017\/12\/GameAspectRatio-300x79.png 300w, https:\/\/www.netexl.com\/blog\/wp-content\/uploads\/2017\/12\/GameAspectRatio-280x74.png 280w\" sizes=\"auto, (max-width: 761px) 100vw, 761px\" \/><\/p>\n<p>We will prepare our assets for two resolutions. 960&#215;640 and 1350&#215;900 and then decide which resolution to use on a particular device based on the pixel width and height of the device. Let us look at the code below<\/p>\n<pre class=\"lang:default decode:true\">var mygame;\r\nvar globalParams = {\r\n\tcalculatedWidth: 1350,\r\n\tcalculatedHeight: 900\r\n}\r\nvar GameResolution = {\r\n    _1350: 1350,\r\n    _960: 960\r\n};\r\n\r\nfunction calculateSize() {\r\n    \/\/ Get Pixel Width and Height of the available space\r\n\tvar w_w = window.innerWidth * window.devicePixelRatio;\r\n    var w_h = window.innerHeight * window.devicePixelRatio;\r\n    var g_w = w_w;\r\n\t\r\n    \/\/ We prepared all assets according to aspect ratio of 1.5\r\n\t\/\/ Since we are going to use different assets for different resolutions, we are not looking at the resolution here\r\n    var originalAspectRatio = 1.5;\r\n\t\/\/ Get the actual device aspect ratio\r\n    var currentAspectRatio = g_w \/ w_h;\r\n    if (currentAspectRatio &gt; originalAspectRatio) {\r\n\t\t\/\/ If actual aspect ratio is greater than the game aspect ratio, then we have horizontal padding \r\n\t\t\/\/ In order to get the correct resolution of the asset we need to look at the height here\r\n\t\t\/\/ We planned for 1350x900 and 960x640 so if height is greater than 640 we pick higher resolution else lower resolution\r\n\t\tif(w_h &gt; 640){\r\n\t\t\tglobalParams.selectedResolution = GameResolution._1350;\r\n\t\t\tglobalParams.calculatedHeight = 900;\r\n\t\t\tglobalParams.calculatedWidth = w_w * (900 \/ w_h); \r\n\t\t} else {\r\n\t\t\tglobalParams.selectedResolution = GameResolution._960;\r\n\t\t\tglobalParams.calculatedHeight = 640;\r\n\t\t\tglobalParams.calculatedWidth = w_w * (640 \/ w_h); \r\n\t\t}\r\n    } else {\r\n\t\t\/\/ If actual aspect ratio is less than the game aspect ratio, then we have vertical padding \r\n\t\t\/\/ In order to get the correct resolution of the asset we need to look at the width here\r\n\t\tif(w_w &gt; 960){\r\n\t\t\tglobalParams.selectedResolution = GameResolution._1350;\r\n\t\t\tglobalParams.calculatedWidth = 1350;\r\n\t\t\tglobalParams.calculatedHeight = w_h * (1350 \/ w_w);\t\t\t\r\n\t\t} else {\r\n\t\t\tglobalParams.selectedResolution = GameResolution._960;\r\n\t\t\tglobalParams.calculatedWidth = 960;\r\n\t\t\tglobalParams.calculatedHeight = w_h * (960 \/ w_w);\t\t\t\r\n\t\t}\r\n    }\r\n}\r\n\r\nwindow.onload = function () {\r\n\tcalculateSize();\r\n    mygame = new Phaser.Game(globalParams.calculatedWidth, globalParams.calculatedHeight, Phaser.AUTO);\t\r\n    mygame.state.add(\"Boot\", boot);\r\n    mygame.state.add(\"Loading\", loading);\r\n    mygame.state.add(\"MainMenu\", MainMenu);\r\n}\r\n<\/pre>\n<p>You will notice we are preparing the game according to pixel size of the device which will then be resized to fit into available space. In the next article we would look into creating game screen and positioning of controls on the screen which is very similar to how we did it in RESIZE mode.<\/p>\n<p>Check out the desktop version of the game <a href=\"http:\/\/www.netexl.com\/games\/traindominoes\/\" target=\"_blank\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my introductory article on this series I talked about using SHOW_ALL scale mode for my game which fits perfectly for need to be responsive. It will resize the game to fit into available space using the original aspect ratio which was used to develop the game. The only issue I saw was the &#8220;letter-boxing&#8221; effect so\u00a0if device&#8217;s aspect ratio was different than the game&#8217;s aspect ratio, there will be blank space around either horizontal edges or vertical edges. We can account for that extra available space when loading new game and positioning of all ui controls can then be done relative to available space which is similar to how we handled RESIZE scale mode. The only difference here is that it can only be done once in SHOW_ALL scale mode when the game is initialized. In mobile app this is not going to be a problem and we can[&#8230;]<\/p>\n","protected":false},"author":5,"featured_media":293,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12,3,19,4],"tags":[],"class_list":["post-689","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-android","category-html5","category-mobile","category-phaser"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/posts\/689","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/comments?post=689"}],"version-history":[{"count":5,"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/posts\/689\/revisions"}],"predecessor-version":[{"id":703,"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/posts\/689\/revisions\/703"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/media\/293"}],"wp:attachment":[{"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/media?parent=689"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/categories?post=689"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/tags?post=689"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}