A rough .gif rendering of the corridor-on-rails concept

Further to my previous post about the potential for a zombie / mutant shooter in which the player moves between locations via a pre-rendered sequence, I have knocked up an extremely rough concept.

Flipping through these frames (320×240) and overlaying a weapon in the lower right corner runs very smoothly on the devices I tested on.
Note: I drew that bio-weapon for a ditched Gameboy Advance project about 12 years ago! I’ve been dying to use it ever since :)

corridor-conceptThe execution needs some tweaking but I think it’s on the right lines just now. I’d like to render some decoration on the walls and ideally texture the walls.
What would follow then is a case of sitting down to figure out every situation and therefore every frame to render.

 

Viewports and the scaling & positioning of the canvas

Having just spent a couple of hours poring over my code for scaling & positioning the game canvas I thought I’d share the experience.

Despite having made several HTML5 games over the last couple of years I’ve never experienced any real issues with scaling or positioning. Just recently however I’ve started to notice inconsistencies between browsers and OS versions.

In some cases the canvas would scale perfectly but not position properly. In other cases the canvas would not scale properly yet position well in the centre of the screen.

My criteria is simple – I want the games to be played in any orientation and to fit consistently in the centre of the screen.
Where full screen is available in either width (landscape orientation games) or height (portrait) I will also aim for that.

It’s 90% there. On Galaxy S2+ and iPhone4+ portrait games load and scale to fit fine in portrait and landscape games load fine and scale in landscape.
The problem arises on iOS when the games are loaded in the wrong orientation.

e.g. if the game is a portrait game and it loads up in portrait mode then it scales to fit just fine, as you would expect. (illustration 1)

ipadscale-portraitload

illustration 1 – game loads in portrait mode

But if the player then decides to play it in landscape it scales fine but doesn’t centre correctly. Just sits to the left of centre. (illustration 2)

illustration 2 - game loaded in portrait and rotated to landscape

illustration 2 – game loaded in portrait and rotated to landscape – note white space where HTML BODY is simply untouched.

If the game loads up in landscape then it centers beautifully and is playable (illustration 3)

iPad HTML5

illustration 3 – game loaded whilst tablet in landscape mode

If the player then rotates to portrait the game scales just fine on iPhone to fit the screen but on iPad it sits rather awkwardly to the right of the screen with about a third of the content out of sight. (illustration 4)

ipadscale-landscapeload-rotate

illustration 4 – loaded in landscape and rotated to portrait

This has an impact on my regional touchEvent code that I use for driving menus and other in-game features.

I no longer present a banner message instructing the player to rotate. It seems clunky and my clients hate it.

Of course it’s far too easy to suggest that as long as the games load up in their preferred orientation then surely I’ll be OK.
The reality is it needs to work and work properly.

So what’s my code doing?

Well surprisingly little.
I certainly don’t sniff the device. It’s 2013. So I don’t actually know I’m dealing with iOS any more than I know it’s a desktop or mobile browser.

The first thing I do is record the screen’s physical width less any scrollbars.

var w = window.innerWidth;
var h = window.innerHeight;

I also record the game’s intended canvas dimensions.

var rw =320;
var rh = 480;

Then to accurately scale the canvas I use the Math.min() method to first determine how best to scale the canvas to preserve the aspect ratio.

multiplier = Math.min((h / rh), (w / rw));
var actualCanvasWidth = rw * multiplier;
var actualCanvasHeight = rh * multiplier;

Fairly simple stuff there just to keep the aspect ratio of the game’s canvas intact and as previously stipulated aim for full screen in the preferred orientation.

To actually position the canvas on the screen I use CSS.

So first I’ve already got a handle on the canvas and stored it within my global namespace (g):

HTML

<body>
<div id="game">
<canvas class="canvas"></canvas>
</div>
</body>

JavaScript

g.gamecanvas = document.getElementById('game');

CSS

.canvas { width: 100%; height: 100%; }

I then make sure that the canvas parent is displaying as a block level element, assign a width to it and use the margin property to centre it. The canvas fits its parent to the pixel.

g.gamecanvas.style.display = "block";
g.gamecanvas.style.width = actualCanvasWidth + "px";
g.gamecanvas.style.height = actualCanvasHeight + "px";
g.gamecanvas.style.margin = "0px auto 0px auto";

My scaling function is called every time the onresize() or onorientationchange() events are fired. It is also called at the very top of the code before the assets are loaded.

So when we tie all this together we get a perfect presentation the first time the game is loaded.
The canvas scales to fit the orientation and centers perfectly in the centre of the screen.

So why on earth do I get that “dead” area when the tablet is rotated from portrait to landscape? (illustration 2 above)
Why does the canvas shift over to the right when the tablet is rotated from landscape to portrait? (illustration 4 above)
There has to be something else to look at.

The answer lay in the META description for the VIEWPORT.

Here’s what I used to present in the index.html of every game:

<meta name="viewport" content="width=320, height=440, user-scalable=no, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />

What a mess. I’d never touched this in almost two years.
Understanding the viewport is essential to understanding mobile presentation. Generally speaking the rule is if you don’t understand how it works don’t use it. The results can be undesirable.

Rather than go to the trouble of fully understanding what the viewport definitions are and do I decided to look at what I actually want to achieve. The answer here is very simple – a) stretch content to screen dimensions, b) suppress ability to pinch / zoom.

There is no need to specify the physical width or height in pixels of the device screen. There is also no need to restrict user scaling with the user-scalable attribute. Finally there is no need to set a maximum-scale, which I must admit I found surprising.

The only code I need here is:

<meta name="viewport" content="width=device-width, initial-scale=1">

The scaling of the canvas and positioning of the parent element within the document body are now perfect. No more “dead” regions and no more strange horizontal positioning.

There appears to be more sympathy for my lousy meta code within Android browsers than there is with iOS and Safari.

Dolphin Browser and Dolphin Browser Beta

Just wanted to quickly reflect some thoughts on Dolphin Browser Beta.

My current test device for HTML5 games is a Samsung Galaxy S3. Quite possibly the best handset money can buy at this moment in time.
There are a range of browsers available for it and I have them all installed. It’s a wonderful feature to be able to launch a game from a shortcut and then select a browser to run it in.

Android browser selection

My current focus is on the Dolphin Browser.
In many respects it’s a wonderful browser to use. Its gesturing for starters makes life very simple. But with regard to executing HTML5 games it’s a dog it falls short of Firefox and Chrome on Android.

Dolphin browser beta logo
Fortunately there is a Dolphin Browser Beta (DBb) which addresses this. Better yet it has an implementation of the Web Audio API. It is this browser that you want of the two Dolphin browsers available for playing your mobile web games on Android.
It still falls some way behind Firefox (the best) and Chrome (a close second) on Android for raw Canvas performance but is a huge leap forward from the default Dolphin browser.

So to the problems I’m experiencing just now.

  1. A distinct lag from the touch interface
  2. Unable to decode MP3 audio files generated from Audacity

Of the two I suspect that number 2 falls under “user error”.
Number 1 on the other hand is annoying.

Executed on the desktop my current project tracks the mouse beautifully such that the player’s ship glides gracefully around the screen. This makes the game extremely playable and comfortable to control.
Moving over to mobile and playing under Firefox and Chrome that same smoothness can be found. A real pleasure to play.
But with DBb there appears to be a tiny lag in firing the touchMove event. This translates in to a dragging effect whereby the player will slide his finger around the screen only to find that his ship is struggling to catch up with the precise location of his touch.

In some respects I quite like it. It adds another dimension but of course it isn’t by design so is unwanted.

This is a minor niggle. The browser’s performance is very good and it also offers a full screen experience as the game launches. Thanks to an implementation of requestAnimationFrame the movement is smooth and makes games a pleasure to view.

My side project, PlayStar.mobi, is due to launch as a feature within the Dolphin Browser beta in the coming months so I am going to keep a close eye on the progress of the browser. I am hoping that it emerges as a strong contender to the more established mobile browsers.

%d bloggers like this: