{"id":778,"date":"2017-12-29T08:25:13","date_gmt":"2017-12-29T08:25:13","guid":{"rendered":"http:\/\/www.netexl.com\/blog\/?p=778"},"modified":"2017-12-29T08:25:13","modified_gmt":"2017-12-29T08:25:13","slug":"how-to-handle-orientation-change-in-phaser-mobile-web-game","status":"publish","type":"post","link":"https:\/\/www.netexl.com\/blog\/how-to-handle-orientation-change-in-phaser-mobile-web-game\/","title":{"rendered":"How to Handle Orientation Change in Phaser Mobile Web Game"},"content":{"rendered":"<p>If you are not using RESIZE mode for mobile game development and using SHOW_ALL or other scale modes, then you would need to lock the game for one specific orientation. In the previous articles we discussed about the mobile game which was to be published to Android store (<a href=\"https:\/\/www.netexl.com\/blog\/making-of-a-responsive-mobile-game-app-using-phaser-introduction\/\" target=\"_blank\">Intoduction<\/a>,\u00a0<a href=\"https:\/\/www.netexl.com\/blog\/making-of-a-responsive-mobile-game-app-using-phaser-calculation-for-game-size\/\" target=\"_blank\">Calculation<\/a>,\u00a0<a href=\"https:\/\/www.netexl.com\/blog\/making-of-a-responsive-mobile-game-app-using-phaser-game-screen\/\" target=\"_blank\">Game Screen<\/a>), I also uploaded the game online. The game was played in Landscape mode and I initially developed it for desktop. When I opened it in mobile, though I could open it in Portrait mode and everything was calculated well, I wanted to lock it for Landscape orientation when opened\u00a0in browser on a mobile device. The orientation was easily locked in Android app by simply changing some configuration option but for browser version I had to write some addtional code. I got some help from <a href=\"http:\/\/www.emanueleferonato.com\/2015\/04\/23\/how-to-lock-orientation-in-your-html5-responsive-game-using-phaser\/\" target=\"_blank\">Emanuele&#8217;s blog on the same topic<\/a> and borrowed some code. I had to handle it differently since I was doing some additional game size calcuation on load and if the game was not loaded in full screen mode then aspect ratio of the game screen was not calculated properly\u00a0(as\u00a0browser address bar was also coming into the picture for aspect ratio calculation) so I decided that the game will only be loaded in Landscape mode and in Portrait mode we will not initialize the game and will ask user to turn the device. When\u00a0user turns the device, we will load the game. Once the game is loaded in correct orientation and then turned to incorect orientation, we will simply overlay\u00a0an image with message to turn device\u00a0and game will continue to run in the background. The changes in the code goes as following<\/p>\n<p>Declare following class in your CSS file (playlandscape.png is the overlay image we want to display on incorrect orientation)<\/p>\n<pre class=\"lang:default decode:true\">#turn{\r\n\twidth:100%;\r\n\theight:100%;\r\n\tposition:fixed;\r\n\ttop:0px;\r\n\tleft:0px;\r\n\tbackground-color:white;\r\n\tbackground-image:url('images\/playlandscape.png');\r\n\tbackground-repeat:no-repeat;\r\n\tbackground-position: center center;\r\n    background-size:contain;\r\n\tdisplay:none;\r\n}<\/pre>\n<p>Add\u00a0a div in the your html (highlighted below)<\/p>\n<pre class=\"lang:default mark:3 decode:true\">&lt;body&gt;\r\n    &lt;div id=\"traindominoes\"&gt;&lt;\/div&gt;\r\n    &lt;div id=\"turn\"&gt;&lt;\/div&gt;\r\n&lt;\/body&gt;<\/pre>\n<p>Declare a flag to check\u00a0which orientaion the game was loaded in. In boot class simply\u00a0assign the orientation (See highlighted lines 2 and 11 below).\u00a0In lines 13, 14, 15\u00a0we fixed the orientation to landscape (set first\u00a0parameter to true for Landscape and second for Portrait) and defined two methods to handle correct\/incorrect orientations.<\/p>\n<pre class=\"lang:default mark:2,11,13,14,15 decode:true\">\/\/ ---------------boot---------------------\r\nvar isInitializedInPotrait;\r\n\r\nboot = {\r\n    init: function () {\r\n    },\r\n    preload: function () {\r\n        mygame.load.image(\"loading\", \"images\/loading.png\");\r\n    },\r\n    create: function () {\r\n        isInitializedInPotrait = mygame.scale.isGamePortrait;\r\n        mygame.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;\r\n        mygame.scale.forceOrientation(true, false);\r\n        mygame.scale.enterIncorrectOrientation.add(handleIncorrect);\r\n        mygame.scale.leaveIncorrectOrientation.add(handleCorrect);\r\n        mygame.scale.setScreenSize = true;\r\n        mygame.stage.scale.pageAlignHorizontally = true;\r\n        mygame.stage.scale.pageAlignVeritcally = true;\r\n        mygame.state.start(\"Loading\");\r\n    }\r\n};\r\n<\/pre>\n<p>Now\u00a0check out the code below which does rest of the work. We modified calculateSize method to check if we are loading on mobile and in Landscape mode. I did a simple check for currentAspectRatio and devicePixelRatio to evaluate this which works well for most use cases (see highlighted).<\/p>\n<pre class=\"lang:default mark:11,12,13 decode:true\">function calculateSize() {\r\n    \/\/ Get Pixel Width and Height of the available space\r\n    var w_w = window.innerWidth * window.devicePixelRatio;\r\n    var w_h = window.innerHeight * window.devicePixelRatio;\r\n    var g_w = w_w;\r\n    \/\/ We prepared all assets according to aspect ratio of 1.5\r\n    \/\/ 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    \/\/ Get the actual device aspect ratio\r\n    var currentAspectRatio = g_w \/ w_h;\r\n    if (currentAspectRatio &lt; 1 &amp;&amp; window.devicePixelRatio !== 1) {\r\n        return false;\r\n    }\r\n    if (currentAspectRatio &gt; originalAspectRatio) {\r\n        \/\/ If actual aspect ratio is greater than the game aspect ratio, then we have horizontal padding \r\n        \/\/ In order to get the correct resolution of the asset we need to look at the height here\r\n        \/\/ We planned for 1350x900 and 960x640 so if height is greater than 640 we pick higher resolution else lower resolution\r\n        if (w_h &gt; 640) {\r\n            globalParams.selectedResolution = GameResolution._1350;\r\n            globalParams.calculatedHeight = 900;\r\n            globalParams.calculatedWidth = w_w * (900 \/ w_h);\r\n        } else {\r\n            globalParams.selectedResolution = GameResolution._960;\r\n            globalParams.calculatedHeight = 640;\r\n            globalParams.calculatedWidth = w_w * (640 \/ w_h);\r\n        }\r\n    } else {\r\n        \/\/ If actual aspect ratio is less than the game aspect ratio, then we have vertical padding \r\n        \/\/ In order to get the correct resolution of the asset we need to look at the width here\r\n        if (w_w &gt; 960) {\r\n            globalParams.selectedResolution = GameResolution._1350;\r\n            globalParams.calculatedWidth = 1350;\r\n            globalParams.calculatedHeight = w_h * (1350 \/ w_w);\r\n        } else {\r\n            globalParams.selectedResolution = GameResolution._960;\r\n            globalParams.calculatedWidth = 960;\r\n            globalParams.calculatedHeight = w_h * (960 \/ w_w);\r\n        }\r\n    }\r\n    return true;\r\n}\r\n\r\nfunction handleIncorrect() {\r\n    if (!mygame.device.desktop) {\r\n        document.getElementById(\"turn\").style.display = \"block\";\r\n    }\r\n}\r\n\r\nfunction handleCorrect() {\r\n    if (!mygame.device.desktop) {\r\n        document.getElementById(\"turn\").style.display = \"none\";\r\n    }\r\n}\r\n\r\nvar mygame;\r\nvar globalParams = {\r\n    calculatedWidth: 1350,\r\n    calculatedHeight: 900\r\n}\r\n\r\nwindow.onload = function () {\r\n    if (calculateSize()) {\r\n        loadGame();\r\n    } else {\r\n        document.getElementById(\"turn\").style.display = \"block\";\r\n        window.addEventListener(\"orientationchange\", onOrientationChange, false);\r\n    }\r\n}\r\n\r\nfunction onOrientationChange() {\r\n    if (typeof isInitializedInPotrait === 'undefined') {\r\n        document.getElementById(\"turn\").style.display = \"none\";\r\n        setTimeout(function () {\r\n            if (calculateSize()) {\r\n                loadGame();\r\n            } else {\r\n                document.getElementById(\"turn\").style.display = \"block\";\r\n            }\r\n        }, 1000);\r\n    }\r\n}\r\n\r\nfunction loadGame() {\r\n    window.removeEventListener(\"orientationchange\", onOrientationChange);\r\n    mygame = new Phaser.Game(globalParams.calculatedWidth, globalParams.calculatedHeight, Phaser.AUTO, \"traindominoes\");\r\n\r\n    mygame.state.add(\"Boot\", boot);\r\n    mygame.state.add(\"Loading\", loading);\r\n    mygame.state.start(\"Boot\");\r\n}<\/pre>\n<p>We had added two methods for handling correct and incorrect orintations in boot class. Phaser calls these methods accordingly based on\u00a0device&#8217;s orientation. In these methods we simply overlay an image on top of game canvas if incorrect orientation or, hide the overlay image if correct orientation. This works well when user has loaded the game in Landscape mode and then turns device to Portrait mode.<\/p>\n<p>If user\u00a0opens the game in Portrait mode, then we don&#8217;t want to load the game. That we are handling in calculateSize method as explained above. If game was opened in incorrect mode then we will simply add\u00a0onOrientationChage event and overlay the message. Once user turns the device to correct orientation, then only we will initialize the game which will give us the perfect calculated screen. Once game is correctly initialized, we won&#8217;t need\u00a0onOrientationChage event so we will remove the event as soon as the game is loaded.<\/p>\n<p>In portrait mode we see the &#8220;turn device&#8221; message as shown below<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-780\" src=\"https:\/\/www.netexl.com\/blog\/wp-content\/uploads\/2017\/12\/WebPortrait1.png\" alt=\"\" width=\"270\" height=\"460\" srcset=\"https:\/\/www.netexl.com\/blog\/wp-content\/uploads\/2017\/12\/WebPortrait1.png 270w, https:\/\/www.netexl.com\/blog\/wp-content\/uploads\/2017\/12\/WebPortrait1-176x300.png 176w, https:\/\/www.netexl.com\/blog\/wp-content\/uploads\/2017\/12\/WebPortrait1-164x280.png 164w\" sizes=\"auto, (max-width: 270px) 100vw, 270px\" \/><\/p>\n<p>When we turn device to correct orientation, it displays the game.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-781\" src=\"https:\/\/www.netexl.com\/blog\/wp-content\/uploads\/2017\/12\/WebPortrait2.png\" alt=\"\" width=\"538\" height=\"278\" srcset=\"https:\/\/www.netexl.com\/blog\/wp-content\/uploads\/2017\/12\/WebPortrait2.png 538w, https:\/\/www.netexl.com\/blog\/wp-content\/uploads\/2017\/12\/WebPortrait2-300x155.png 300w, https:\/\/www.netexl.com\/blog\/wp-content\/uploads\/2017\/12\/WebPortrait2-280x145.png 280w\" sizes=\"auto, (max-width: 538px) 100vw, 538px\" \/><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you are not using RESIZE mode for mobile game development and using SHOW_ALL or other scale modes, then you would need to lock the game for one specific orientation. In the previous articles we discussed about the mobile game which was to be published to Android store (Intoduction,\u00a0Calculation,\u00a0Game Screen), I also uploaded the game online. The game was played in Landscape mode and I initially developed it for desktop. When I opened it in mobile, though I could open it in Portrait mode and everything was calculated well, I wanted to lock it for Landscape orientation when opened\u00a0in browser on a mobile device. The orientation was easily locked in Android app by simply changing some configuration option but for browser version I had to write some addtional code. I got some help from Emanuele&#8217;s blog on the same topic and borrowed some code. I had to handle it differently[&#8230;]<\/p>\n","protected":false},"author":5,"featured_media":293,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,19,4],"tags":[],"class_list":["post-778","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-html5","category-mobile","category-phaser"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/posts\/778","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=778"}],"version-history":[{"count":5,"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/posts\/778\/revisions"}],"predecessor-version":[{"id":787,"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/posts\/778\/revisions\/787"}],"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=778"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/categories?post=778"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.netexl.com\/blog\/wp-json\/wp\/v2\/tags?post=778"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}