{"id":2501,"date":"2014-10-26T17:18:28","date_gmt":"2014-10-26T21:18:28","guid":{"rendered":"http:\/\/www.rocketshipgames.com\/blogs\/tjkopena\/?p=2501"},"modified":"2022-07-01T13:32:31","modified_gmt":"2022-07-01T17:32:31","slug":"fullscreen-scaling-in-phaser","status":"publish","type":"post","link":"https:\/\/www.rocketshipgames.com\/blogs\/tjkopena\/2014\/10\/fullscreen-scaling-in-phaser\/","title":{"rendered":"Fullscreen Scaling in Phaser"},"content":{"rendered":"<p>This weekend I&#8217;ve been playing a bit with nailing down multi-device scaling in <a href=\"http:\/\/phaser.io\/\">Phaser<\/a> games. This was a bit more\u00a0confusing than I expected, but I mostly figured out why and thought I&#8217;d share.<\/p>\n<p><em><strong>Update:<\/strong> I&#8217;ve posted <a href=\"https:\/\/github.com\/RocketshipGames\/phaser-fullscreen\">this example and a state-based project template<\/a> to GitHub.<\/em><\/p>\n<p>My\u00a0objectives were\u00a0very simple:<\/p>\n<ul>\n<li>Set logical view\u00a0dimensions around which the game will be based;<\/li>\n<li>Scale the game to\u00a0fill the available window when loaded, maintaining aspect ratio and content;<\/li>\n<li>Upon clicking have\u00a0the game go fullscreen and scale to fill\u00a0the screen, maintaining aspect ratio and content.<\/li>\n<\/ul>\n<p>This minimal example demonstrates those\u00a0(click to fullscreen, again to return):<\/p>\n\n<!-- iframe plugin v.6.0 wordpress.org\/plugins\/iframe\/ -->\n<iframe loading=\"lazy\" src=\"http:\/\/rocketshipgames.com\/tmp\/20141026-scaletest.html\" width=\"100%\" height=\"300\" allowfullscreen=\"true\" webkitallowfullscreen=\"true\" mozallowfullscreen=\"true\" scrolling=\"yes\" class=\"iframe-class\" frameborder=\"0\"><\/iframe>\n\n<p>&nbsp;<\/p>\n<p>In the blog view here the game has been placed inside a 300px iframe and scales down accordingly from an 800&#215;600 logical view. After you click it scales up to fill the screen as much as it can without losing content. All of this is using\u00a0Phaser 2.1.3, the latest release. Note that this is just in Chrome &#038; Chromium. Desktop Firefox seems to have have wholly separate <a href=\"https:\/\/github.com\/photonstorm\/phaser\/issues\/1256\">issues<\/a>, and on Android Firefox fullscreening doesn&#8217;t seem to do anything.<\/p>\n<p>This test is extremely similar to Phaser&#8217;s\u00a0<a href=\"http:\/\/examples.phaser.io\/_site\/view_full.html?d=display&amp;f=fullscreen+buttons.js&amp;t=fullscreen%20buttons\">dragon<\/a> and <a href=\"http:\/\/examples.phaser.io\/_site\/view_full.html?d=display&amp;f=fullscreen.js&amp;t=fullscreen\">anime<\/a> fullscreen examples\u00a0as well as its <a href=\"https:\/\/github.com\/photonstorm\/phaser\/tree\/master\/resources\/Project%20Templates\/Full%20Screen%20Mobile\">Full Screen Mobile project template<\/a>. However, those have a couple issues and do\u00a0not work ideally\u00a0for me on both my desktop (Linux laptop, Chromium) and phone (Galaxy S3, Chrome). In the end the problems\u00a0were small but critical.<\/p>\n<p>First, Phaser&#8217;s ScaleManager has an <a href=\"http:\/\/docs.phaser.io\/Phaser.ScaleManager.html\">undocumented<\/a>\u00a0property <code>fullScreenScaleMode<\/code> that controls how games scale in fullscreen mode. The\u00a0examples use this. The project template however uses the property <code>scaleMode<\/code>. It&#8217;s fairly easy to miss that these are using different properties, and that the fullscreen variant\u00a0even exists. Further,\u00a0it seems you actually have to set both to get the expected behavior, at least for <code>SHOW_ALL<\/code> scaling and my two\u00a0platforms. The code below has a simple chart of the effects under various combinations of setting or not setting <em>both<\/em> of these.<\/p>\n<p>Second, the ScaleManager property <code>pageAlignHorizontally<\/code> seems to have a <a href=\"https:\/\/github.com\/photonstorm\/phaser\/issues\/1255\">bug<\/a>. In windowed mode it works as expected, but in fullscreen it actually causes the game to be horizontally off-centered. For the moment I&#8217;m planning to put the game into a container <code>div<\/code> to center in windowed mode.\u00a0Phaser seems to take care of centering the game\u00a0in fullscreen\u00a0mode even without this being set. I haven&#8217;t diagnosed\u00a0this further. My guess is the base code is setting a left margin to center the game if the property is set, and then fullscreen mode applies a left margin again without checking to see if that has already been done.<\/p>\n<p>Third, it&#8217;s not clear from the examples and docs what of Phaser&#8217;s <a href=\"http:\/\/docs.phaser.io\/Phaser.ScaleManager.html\">ScaleManager\u00a0API<\/a> is needed and what is not. The project template in particular does several things that don&#8217;t seem to matter, for example calling <code>ScaleManager::setScreenSize()<\/code>. Removing that seems to have no effect with these settings, though the docs say it&#8217;s necessary. Conversely, it is important to call <code>ScaleManager::refresh()<\/code> to have the game scale at the start. Otherwise you have to go fullscreen or cause another window change to have the settings apply. The examples however don&#8217;t call this.<\/p>\n<p>In any event, after finally identifying all these the test seems to work well on both my laptop and phone. Code is as follows:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n&lt;html&gt;\r\n&lt;head&gt;\r\n  &lt;script src=&quot;\/deps\/phaser-2.1.3-arcade-min.js&quot;&gt;&lt;\/script&gt;\r\n&lt;\/head&gt;\r\n\r\n&lt;body style=&quot;margin:0px; padding: 0px;&quot;&gt;\r\n&lt;div id=&quot;game&quot;&gt;&lt;\/div&gt;\r\n\r\n&lt;script type=&quot;text\/javascript&quot;&gt;\r\nvar game = new Phaser.Game(800, 600, Phaser.CANVAS, 'game',\r\n  { preload: preload, create: create });\r\n\r\nfunction preload() {\r\n  game.stage.backgroundColor = '#336699';\r\n  game.load.image('logo', '20141026-scaletest-logo.png');\r\n}\r\n\r\nfunction create() {\r\n\r\n  \/\/ Put a graphic in the center to demonstrate.\r\n  sprite = game.add.sprite(game.world.centerX, game.world.centerY, 'logo');\r\n  sprite.anchor.set(0.5);\r\n\r\n  \/*\r\n   * How the following modes take affect.\r\n   *\r\n   * On a laptop (Linux, Chromium browser):\r\n   *   FS Scale  Reg Scale Reg Result  FS Result\r\n   *   On        On        Fills       Fills\r\n   *   On        Off       Unscaled    Fills\r\n   *   Off       On        Fills       Unscaled\r\n   *   Off       Off       Unscaled    Unscaled\r\n   *\r\n   * On a phone (Galaxy S3, Chrome browser):\r\n   *   FS Scale  Reg Scale N Result    FS Result\r\n   *   On        On        Fills       Fills\r\n   *   On        Off       Too big     Unscaled\r\n   *   Off       On        Fills       Unscaled; buggy\r\n   *   Off       Off       Too big     Exact fit\r\n   *\r\n   *\/\r\n  game.scale.fullScreenScaleMode = Phaser.ScaleManager.SHOW_ALL;\r\n  game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;\r\n\r\n  \/\/ Properly centers game in windowed mode, but aligning\r\n  \/\/ horizontally makes it off-centered in fullscreen mode.\r\n  \/\/game.scale.pageAlignHorizontally = true;\r\n  \/\/game.scale.pageAlignVertically = true;\r\n\r\n  \/\/ Docs say this is necessary, but it doesn't seem to change behavior?\r\n  \/\/game.scale.setScreenSize(true);\r\n\r\n  \/\/ This is necessary to scale before waiting for window changes.\r\n  game.scale.refresh();\r\n\r\n  game.input.onDown.add(gofull, this);\r\n\r\n}\r\n\r\nfunction gofull() {\r\n  if (game.scale.isFullScreen) {\r\n    game.scale.stopFullScreen();\r\n  } else {\r\n    game.scale.startFullScreen(false);\r\n  }\r\n}\r\n&lt;\/script&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>This weekend I&#8217;ve been playing a bit with nailing down multi-device scaling in Phaser games. This was a bit more\u00a0confusing than I expected, but I mostly figured out why and thought I&#8217;d share. Update: I&#8217;ve posted this example and a state-based project template to GitHub. My\u00a0objectives were\u00a0very simple: Set logical view\u00a0dimensions around which the game &hellip; <a href=\"https:\/\/www.rocketshipgames.com\/blogs\/tjkopena\/2014\/10\/fullscreen-scaling-in-phaser\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":3540,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[58],"tags":[104,162,242,277],"class_list":["post-2501","post","type-post","status-publish","format-standard","hentry","category-code","tag-html5","tag-javascript","tag-phaser","tag-videogames"],"_links":{"self":[{"href":"https:\/\/www.rocketshipgames.com\/blogs\/tjkopena\/wp-json\/wp\/v2\/posts\/2501","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.rocketshipgames.com\/blogs\/tjkopena\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.rocketshipgames.com\/blogs\/tjkopena\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.rocketshipgames.com\/blogs\/tjkopena\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.rocketshipgames.com\/blogs\/tjkopena\/wp-json\/wp\/v2\/comments?post=2501"}],"version-history":[{"count":10,"href":"https:\/\/www.rocketshipgames.com\/blogs\/tjkopena\/wp-json\/wp\/v2\/posts\/2501\/revisions"}],"predecessor-version":[{"id":2515,"href":"https:\/\/www.rocketshipgames.com\/blogs\/tjkopena\/wp-json\/wp\/v2\/posts\/2501\/revisions\/2515"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.rocketshipgames.com\/blogs\/tjkopena\/wp-json\/wp\/v2\/media\/3540"}],"wp:attachment":[{"href":"https:\/\/www.rocketshipgames.com\/blogs\/tjkopena\/wp-json\/wp\/v2\/media?parent=2501"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.rocketshipgames.com\/blogs\/tjkopena\/wp-json\/wp\/v2\/categories?post=2501"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.rocketshipgames.com\/blogs\/tjkopena\/wp-json\/wp\/v2\/tags?post=2501"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}