Jump to content

Resizing a game in Safari


Recommended Posts

I've been trying to sell my first html5 game and I've had a few bites, but they've come back to me saying that it doesn't resize on orientation change correctly when viewed in Safari on iOS.

 

The game has almost square dimension (476x500) so I've tried to code it so that it's just as happy landscape as portrait and simply resizes when the user turns the phone. It works fine on Android and it initially resizes correctly on Safari, but when the user turns their phone it goes a bit haywire.

 

I've been googling and trying different things but I still can't get it to work properly. I'm really hoping I've done something obviously wrong and stupid that someone here can point out.

 

The actual game can be found here

Here's a test to make sure the function and values were there correctly.

 

Here's my code (I do have the function.bind workaround so I know it's not that).

 

//Relevant html//-----------------------------------------------------------------------//<head>    <meta name="viewport" content="user-scalable=0, width=device-width, height=device-height" />    <meta name="apple-mobile-web-app-capable" content="yes" /></head><body>    <div id="content">        <canvas id="gameCanvas" width="476" height="500"></canvas>    </div></body> //Base CSS//-----------------------------------------------------------------------//body{    background-color: #1a1a22;    margin:0;    padding:0;} #content {    position: absolute;    width: 100%;    height: 100%; } #gameCanvas {} //Resize code//-----------------------------------------------------------------------//Main.prototype.onResize = function () {        createjs.Tween.get(this).wait(200).call(this.adjustRatio.bind(this));        //this.adjustRatio();};Main.prototype.adjustRatio = function () {        var img = document.getElementById("gameCanvas");        if(window.innerHeight < window.innerWidth) {            img.style.height = '100%';            img.style.width = 'auto';            var gameWidth = window.innerHeight / 500 * 476;            var gameHeight = window.innerHeight;        } else {            img.style.width = '100%';            img.style.height = 'auto';            gameWidth = window.innerWidth;            gameHeight = window.innerWidth / 476 * 500;        }        var content = document.getElementById("content");        content.style.left = (window.innerWidth - gameWidth) / 2 + "px";};
Link to comment
Share on other sites

I think you need to revisit the logic in your adjustRatio function.

You only declare the local variables var gameWidth and var gameHeight inside the if clause:

if(window.innerHeight < window.innerWidth

but you also reference them in the other side of that clause, ie when window.innerHeight < window.innerWidth evaluates to false - but at this point the local variables gameWidth and gameHeight have not been declared. I guess that doing this probably creates them as variables in the global scope or something, but whatever the case I think this is likely to have unpredictable results.

Link to comment
Share on other sites

I'm new to javascript but I can't imagine that's how it would scope the variables, and I would be appalled if it does work like that. I wrote it using Typescript and that gives you compile errors if you try to use non scoped variable inside a class, so I would have hoped that would keep you from making that kind of errors too.

 

I made the change anyhow and it's didn't seem to make a difference.

 

After lots and lots of searching with different keywords I found this http://filamentgroup.com/lab/a_fix_for_the_ios_orientationchange_zoom_bug/ which implies there actually is a bug with Safari (how often is this actually true? A bug with the browser rather that your code? Almost never in my experience). Unfortunately their fix doesn't seem to work either. I'm thinking of simply removing the ability to rotate. Can you think of another game that does this that I could look at? I can't - almost every game I've seen on this forum uses the css orientation visible thing to fix it to either portrait or landscape.

Link to comment
Share on other sites

Thanks you so much for that.

Being able to look at your code made it possible for me to analyse exactly what I was doing differently, and after several blind alleys I finally cracked it.

 

It turns out that I was setting the style size on my canvas element rather than the div containing it. For some reason on Safari it simply wasn't resizing correctly when you rotate the screen, though it works on other browsers. Changing the resizing to the containing div fixed it.

 

Whilst looking for this I found an issue with the stock Android browser, where after rotating there is sometimes a slight delay before the innerWidth/innerHeight update, hence the 200 millisecond delay in calling the resize code.

Link to comment
Share on other sites

I think it's more related to the underlying reflow that triggers asynchronously.

 

A former colleague at Zynga, Paul, solved it by applying a height that is bigger than the actual viewport on the document.documentElement and "heuristically" detecting if the viewport got bigger or not. This is very hacky, and I definitely would not recommend it.

 

My solution inside lycheeJS waits for the reflow and triggers the viewport resize when it is actually ready - not when only the DOM inside is ready. The conceptual problem with the window based API is that the resize and orientationchange events are triggered if the DOM hasn't done the reflow, so the sizes and stylesheets (etc. pp.) are applied later, right after the next javascript callstack due to the relayouting and reflowing taking place next.

 

This conceptual problem is really hard to debug, as the offset properties are calculated inside the relayouting step and the values themselves (inside the console, or inside any synchronous API like document.alert) are dependent on the reflow and linked. To solve the problem, I'm caching the last orientationchange event's timestamp and only firing an event for each resize event if the new orientationchange event was fired already and it's offset values (like width/height of viewport) are calculated already.

 

 

Have a look at this file, it might give you a clue:

 

https://github.com/martensms/lycheeJS/blob/master/lychee/platform/html/Viewport.js#L43

 

~Cheers

Link to comment
Share on other sites

  • 3 months later...

Bit of a vampire post here, as last post was about 3 months ago - stumbled across this by looking up all lychee.js cross-references.  But I digress.

 

Regarding the post by Alex about the scoping of the gameWidth and gameHeight variables... JavaScript does not have the concept of "block scope".  So, unlike most other C-syntax-like languages, curly braces do not establish new scope.  The gameWidth and gameHeight variables enjoy function scope here, so the original code is not deficient on that account.  To learn more, look up the concept of JavaScript "hoisting".  You can find it in any definitive JavaScript book and I'm thus I'm certain that you can find a thorough explanation on the Web.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...