HTML5 Game Development Blog

  • Tiled Game Engine slide



Cross platform HTM5 games – mobile support

Category : JavaScript, Tiled Game Engine Mar 19th, 2015

mobile-head

HTML5 is very powerful platform for game development – it should work with no problems on any modern browsers, even on mobile browsers. But going mobile is not so straight forward – we should take into account touch support, screen orientation and several more tricks. Let’s deep into details.

Disable zoom on mobile view

You’ve spend tons of time to create your game, set up a lot of experiments with user experience and finally released your game to the world. If you’re targeting only on the desktop segment – no issues. But games, in most cases, will be launched on mobiles and that’s an issue.

Double touch in Android browser (native or Chrome at least) will cause page zoom. That’s also is valid for Safari for iOS – it will zoom the page. In that case our player will get terrible user experience – no UI on the screen (or it will be cropped), dragging in most cases will not do what expected (no page scroll, but view port moving) and other terrible experience, that will push player to drop our game. That is not what we want.

To “tell” the mobile browser that your page is not going to need zooming – which can be done using a fixed view port. It is can be made by inserting special meta tag in the home page:

<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />

This code will set page width to the device width and fully disable as pinch zoom. So, now you page will not be zoomed neither by user nor by browser.

Good detailed reading about view port meta-tag available on Apple developers site

 In the Tiled Game Engine (starting from v0.0.3) it will be done automatically while creating view port

Handling touch events

Touch events is not the same as mouse event. With mouse we can hover over element and show some tool tip, but not with touch. But modern laptops supports both mouse and touches and we should not select which interaction type to support.

It is not reasonable, from my point of view, to support touch events separately. But it make sense to process touch events to emulate mouse events.

So, we should start with event handlers for touch events. Tiled Game Engine listens touches in the view port. Event handlers installed during view port initialization, if device supports touches:

    function ViewPort(tag, width, height) {
        ...
        // touch events
		if (TiledGameEngine.Device && TiledGameEngine.Device.touch) {
            this.touchHistory = [];
			this.domViewport.addEventListener("touchstart", 	throttle(this.touchHandler, 16, this), true);
			this.domViewport.addEventListener("touchmove", 		throttle(this.touchHandler, 16, this), true);
			this.domViewport.addEventListener("touchend", 		throttle(this.touchHandler, 16, this), true);
			this.domViewport.addEventListener("touchcancel", 	throttle(this.touchHandler, 16, this), true);
		}
        ...
    }

Noticed, I use my handy throttle function to decrease events processing. Throttle function described in details in that post.

Event handler code is a bit tricky, as far I do not want to handle “tap” event, but still need to handle “click” event. So I collect event sequence and then analyze it. Actually touch handlers works like a proxy:

	ViewPort.prototype.touchHandler = function(e) {
        // stop default event processing
        e.preventDefault();
        
        // get touch event
		var touch = e.changedTouches[0],
            type = e.type;
		
        // add this event to the touch history
		this.touchHistory[this.touchHistory.length] = e.type;
		
        // analyze event sequences
		if (this.touchHistory.length > 3) {
			this.touchHistory.shift();
		}
		
		var h = this.touchHistory;
		var l = h.length;
		if (l > 1) {
			if (h[l-1] === "touchend") {
				if (h[l-2] === "touchstart" || (l === 3 && h[l-3] === "touchstart")) {
					type = "tap";
				}			
			} else if (h[l-1] === "touchmove") {
				if (h[l-2] === "touchstart") { // ignore that event
					return;
				}
			}
		}

        // simulate mouse events
		var simulatedEvent = document.createEvent("MouseEvent");
			simulatedEvent.initMouseEvent({
			touchstart: "mousedown",
			touchmove: "mousemove",
			touchend: "mouseup",
			tap: "click"
		}[type], true, true, window, 1,
			touch.screenX, touch.screenY,
			touch.clientX, touch.clientY, false,
			false, false, false, 0, null);

		touch.target.dispatchEvent(simulatedEvent);
	};

So, now our code is cross-platform 😉 It handles mouse events as a primary event source, but touches also supported. And we have one actual event handlers set to operate with input.

Lock screen orientation

Screen orientation API allows change web-page orientation to the one we need. In spite of API specification is still in the draft mode (on March, 2015) it is supported by all major browsers. Actually there are 2 API implementation version – initial and new one. Before we go deeper in code let’s cover basis – what it is and why we need it?

Using this API we can detect device orientation (portrait or landscape) and lock screen orientation in the way we need. Actually, the specification states that as a security condition a user agent (read browser) may allow the lock of the screen only if the page is in full screen mode. But my experiments shows that at least on my mobile it is not required and I can set screen orientation without entering to full screen.

Well, back to the code. There are 2 methods that we’re actually interested in (I’ll focus on new version of API implementation, as far old one not interesting anymore):

  • screen.orientation.lock(value) – accepts string to specify the orientations we want to lock the screen at. Possible values:
    • any: The devices is able to be locked in any orientation it can assume. The actual orientations depend on the device, for example the Samsung Galaxy S3 can’t be locked in portrait secondary (upside down).
    • natural: The device is in its natural orientation. For a smartphone this usually means in its primary portrait mode (with the buttons in direction of the ground).
    • portrait-primary: The orientation is in the primary portrait mode with the buttons at the bottom.
    • portrait-secondary: The orientation is in the secondary portrait mode with the buttons at the top (the device is down under)
    • landscape-primary: The orientation is in the primary landscape mode with the buttons at the right.
    • landscape-secondary: The orientation is in the secondary landscape mode with the buttons at the left.
    • landscape – equivalent to landscape-primary
    • portrait– equivalent to portrait-primary
  • unlock() – method is used to release a previously set lock.

I recommend to use either landscape or portrait values, as far it will be matched automatically to the device native values.

The difference in the API implementation between initial version and current one is so huge, that I decide to cover it in the ViewPort class, so you do not need to worry about it. Starting from v0.0.3 ViewPort class provide the following screen orientation API:

    /**
     * Lock the screen orientation, if possible
     * @param   {string}    val     Screen orientation value. Possible values:
     *                              any                 The devices is able to be locked in any orientation it can assume
     *                              natural             The device is in its natural orientation. For a smartphone this 
     *                                                  usually means in its primary portrait mode (with the buttons in 
     *                                                  direction of the ground).
     *                              portrait            see #portrait-primary
     *                              landscape           see #landscape-primary
     *                              portrait-primary    The orientation is in the primary portrait mode with the buttons 
     *                                                  at the bottom.
     *                              portrait-secondary  The orientation is in the secondary portrait mode with the buttons 
     *                                                  at the top (the device is down under)
     *                              landscape-primary   The orientation is in the primary landscape mode with the buttons 
     *                                                  at the right.
     *                              landscape-secondary The orientation is in the secondary landscape mode with the buttons at the left.
     */
    ViewPort.prototype.lockOrientation(val);
    /**
     * Release a previously set lock orientation
     */
    ViewPort.prototype.unlockOrientation();

Conclusion

Going mobile, from technical perspective, is not very hard if you have a proper tools. Tiled Game Engine (v0.0.3+) provide all tools required to handle mobiles touch events, screen orientation and trick with page zooming.

Source code, as usual, available on GitHub.

Watch Issue Star


SHARE :

Leave a Reply

Your email address will not be published.


Like it? Share It!

We're making our best to provide good and valuable content. Please help us by clicking on one of the social icons, thanks for everything.