Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Revision 1109583 of Mobile touch controls

  • Revision slug: Games/Techniques/Control_mechanisms/Mobile_touch
  • Revision title: Mobile touch controls
  • Revision id: 1109583
  • Created:
  • Creator: chrisdavidmills
  • Is current revision? No
  • Comment

Revision Content

{{NextMenu("Games/Techniques/Control_mechanisms/Desktop_with_mouse_and_keyboard", "Games/Techniques/Control_mechanisms")}}

The future of mobile gaming is definitely web, and many developers choose the mobile first approach in their game development process — in the modern world, this generally also involves inplementing touch controls. In this tutorial we will see how easy it is to implement mobile controls in an HTML5 game, and enjoy playing on a mobile touch-enabled device.

Note: The game Captain Rogers is built with Phaser and managing the controls is Phaser-based, but it could also be done in pure JavaScript. The good thing about using Phaser is that it offers helper variables and functions for easier and faster development, but it's totally up to you which approach you choose.

Pure JavaScript approach

We could implement touch events on our own — setting up event listeners and assigning relevant functions to them would be quite straightforward:

var el = document.getElementsByTagName("canvas")[0];
el.addEventListener("touchstart", handleStart, false);
el.addEventListener("touchmove", handleMove, false);
el.addEventListener("touchend", handleEnd, false);
el.addEventListener("touchleave", handleLeave, false);
el.addEventListener("touchcancel", handleCancel, false);

This way, touching the game's {{htmlelement("canvas")}} on the mobile screen would emit events and thus we could manipulate the game in any way we want (for example, moving the space ship around). The events are as follows:

  • touchstart is fired when the user puts a finger on the screen.
  • touchmove is fired when they move the finger on the screen while touching it
  • touchend is fired when the user stops touching the screen
  • touchleave is fired when the user moves their finger outside of the area listening for events.
  • touchcancel when a touch is cancelled, for example when the user moves their finger outside of the screen.

Note: The touch events reference article provides more examples and information.

Touch events in Phaser

We don't have to do this on our own; frameworks like Phaser offer systems for managing touch events for us — see managing the touch events.

Pointer theory

A pointer represents a single finger on the touch screen. Phaser starts two pointers by default, so two fingers can perform an action at once. Captain Rogers is a simple game — it can be controlled by two fingers, the left one moving the ship and the right one contolling the ship's gun. There's no multitouch or gestures — everything is handled by single pointer inputs.

You can add more pointers to the game by using this.game.input.addPointer; up to ten pointers can be managed simultaneously. The most recently used pointer is available in the this.game.input.activePointer object — the most recent finger active on the screen.

If you need to access a specific pointer, they are all available at this.game.input.pointer1, this.game.input.pointer2, etc. They are assigned dinamically, so if you put three fingers on the screen, then pointer1, pointer2, and pointer3 will be active. Removing the second finger for example won't affect the other two, and putting it back again will use the first available property, so pointer2 will be used again.

You can easily get the coordinates of the most recently active pointer via the this.game.input.x and this.game.input.y variables.

Input events

Instead of using the pointers directly it is also possible to listen for this.game.input events, like onDown, onUp, onTap and onHold:

this.game.input.onDown.add(itemTouched, this);

function itemTouched(pointer) {
    // do something
}

The itemTouched() function will be executed when the onDown event is dispatched by touching the screen. The pointer variable will contain the information about the pointer that activated the event.

This approach uses the generally available this.game.input object, but you can also detect the actions on any game objects like sprites or buttons by using onInputOver, onInputOut, onInputDown, onInputUp, onDragStart, or onDragStop:

this.button.events.onInputOver.add(itemTouched, this);

function itemTouched(button, pointer) {
    // do something
}

That way you'll be able to attach an event to any object in the game, like the player's ship, and react to the actions performed by the user.

An additional advantage of using Phaser is that the buttons you create will take any type of input, whether it's a touch on mobile or a click on desktop — the framework sorts this out in the background for you.

Implementation

The easiest way to add an interactive object that will listen for user input is to create a button:

var buttonEnclave = this.add.button(10, 10, 'logo-enclave', this.clickEnclave, this);

This one is created in the MainMenu state — it will be placed ten pixels from the top left corner of the screen, use the logo-enclave image, and execute the clickEnclave() function when it is touched. This will work on mobile and desktop out of the box. There are a few buttons in the main menu, including the one that will actually start the game.

For the actual gameplay, instead of creating more buttons and covering the small mobile screen with them, we can use something a little bit different: we'll create invisible areas which respond to the given action. From a design point of view it is better to make the area of action bigger without covering half of the screen with button images. For example, tapping on the right side of the screen will fire the weapon:

this.buttonShoot = this.add.button(this.world.width*0.5, 0, 'button-alpha', null, this);
this.buttonShoot.onInputDown.add(this.goShootPressed, this);
this.buttonShoot.onInputUp.add(this.goShootReleased, this);

The code above will create a new button using a transparent image that covers the right half of the screen. You can assign functions on input down and input up separately if you'd like to perform more complicated actions, but in this game touching the right side of the screen will simply fire the bullets to the right — this is all we need in this case.

Moving the player could be managed by creating the four directional buttons, but we can take the advantage of touch screens and drag the player's ship around:

var player = this.game.add.sprite(30, 30, 'ship');
player.inputEnabled = true;
player.input.enableDrag();
player.events.onDragStart.add(onDragStart, this);
player.events.onDragStop.add(onDragStop, this);

function onDragStart(sprite, pointer) {
    // do something when dragging
}

We can drag the ship around and do something in the meantime, and react when the drag is stopped.

Dedicated plugins

You could go even further and use dedicated plugins like Virtual Joystick — this is a paid, official Phaser plugin, but you can find free and open source alternatives. The initialization of Virtual Joystick looks like this:

this.pad = this.game.plugins.add(Phaser.VirtualJoystick);
this.stick = this.pad.addStick(30, 30, 80, 'generic');

In the create() function of the Game state we're creating a virtual pad and a generic stick that has four directional virtual buttons by default. This is placed 30 pixels from the top and left edges of the screen and is 80 pixels wide.

The stick being pressed can be handled during the gameplay in the update function like so:

if(this.stick.isDown) {
    // move the player
}

We can adjust the player's velocity based on the current angle of the stick and move him appropriately.

Summary

That covers adding touch controls for mobile; in the next article we'll see how to add keyboard and mouse support.

{{NextMenu("Games/Techniques/Control_mechanisms/Desktop_with_mouse_and_keyboard", "Games/Techniques/Control_mechanisms")}}

Revision Source

<p>{{NextMenu("Games/Techniques/Control_mechanisms/Desktop_with_mouse_and_keyboard", "Games/Techniques/Control_mechanisms")}}</p>

<p class="summary">The future of mobile gaming is definitely web, and many developers choose the <a href="/en-US/docs/Web/Apps/Mobile_First">mobile first</a> approach in their game development process — in the modern world, this generally also involves inplementing touch controls. In this tutorial we will see how easy it is to implement mobile controls in an HTML5 game, and enjoy playing on a mobile touch-enabled device.</p>

<p class="note"><strong>Note</strong>: The game <a href="https://rogers2.enclavegames.com/demo/">Captain Rogers</a> is built with Phaser and managing the controls is Phaser-based, but it could also be done in pure JavaScript. The good thing about using Phaser is that it offers helper variables and functions for easier and faster development, but it's totally up to you which approach you choose.</p>

<h2 id="Pure_JavaScript_approach">Pure JavaScript approach</h2>

<p>We could implement touch events on our own — setting up event listeners and assigning relevant functions to them would be quite straightforward:</p>

<pre class="brush: js">
var el = document.getElementsByTagName("canvas")[0];
el.addEventListener("touchstart", handleStart, false);
el.addEventListener("touchmove", handleMove, false);
el.addEventListener("touchend", handleEnd, false);
el.addEventListener("touchleave", handleLeave, false);
el.addEventListener("touchcancel", handleCancel, false);</pre>

<p>This way, touching the game's {{htmlelement("canvas")}} on the mobile screen would emit events and thus we could manipulate the game in any way we want (for example, moving the space ship around). The events are as follows:</p>

<ul>
 <li><a href="/en-US/docs/Web/API/GlobalEventHandlers/ontouchstart">touchstart</a> is fired when the user puts a finger on the screen.</li>
 <li><a href="/en-US/docs/Web/API/GlobalEventHandlers/ontouchmove">touchmove</a> is fired when they move the finger on the screen while touching it</li>
 <li><a href="/en-US/docs/Web/API/GlobalEventHandlers/ontouchend">touchend</a> is fired when the user stops touching the screen</li>
 <li><a href="/en-US/docs/Web/Events/touchleave">touchleave</a> is fired when the user moves their finger outside of the area listening for events.</li>
 <li><a href="/en-US/docs/Web/API/GlobalEventHandlers/ontouchcancel">touchcancel</a> when a touch is cancelled, for example when the user moves their finger outside of the screen.</li>
</ul>

<div class="note">
<p><strong>Note</strong>: The <a href="/en-US/docs/Web/API/Touch_events">touch events</a> reference article provides more examples and information.</p>
</div>

<h2 id="Touch_events_in_Phaser">Touch events in Phaser</h2>

<p>We don't have to do this on our own; frameworks like Phaser offer systems for managing touch events for us — see <a href="https://phaser.io/docs/2.6.1/Phaser.Touch.html">managing the touch events</a>.</p>

<h3 id="Pointer_theory">Pointer theory</h3>

<p>A <a href="https://phaser.io/docs/2.6.1/Phaser.Pointer.html">pointer</a> represents a single finger on the touch screen. Phaser starts two pointers by default, so two fingers can perform an action at once. Captain Rogers is a simple game — it can be controlled by two fingers, the left one moving the ship and the right one contolling the ship's gun. There's no multitouch or gestures — everything is handled by single pointer inputs.</p>

<p>You can add more pointers to the game by using <code>this.game.input.addPointer</code>; up to ten pointers can be managed simultaneously. The most recently used pointer is available in the <code>this.game.input.activePointer</code> object — the most recent finger active on the screen.</p>

<p>If you need to access a specific pointer, they are all available at <code>this.game.input.pointer1</code>, <code>this.game.input.pointer2</code>, etc. They are assigned dinamically, so if you put three fingers on the screen, then <code>pointer1</code>, <code>pointer2</code>, and <code>pointer3</code> will be active. Removing the second finger for example won't affect the other two, and putting it back again will use the first available property, so <code>pointer2</code> will be used again.</p>

<p>You can easily get the coordinates of the most recently active pointer via the <code>this.game.input.x</code> and <code>this.game.input.y</code> variables.</p>

<h3 id="Input_events">Input events</h3>

<p>Instead of using the pointers directly it is also possible to listen for <code>this.game.input</code> events, like <code>onDown</code>, <code>onUp</code>, <code>onTap</code> and <code>onHold</code>:</p>

<pre class="brush: js">
this.game.input.onDown.add(itemTouched, this);

function itemTouched(pointer) {
    // do something
}</pre>

<p>The <code>itemTouched()</code> function will be executed when the <code>onDown</code> event is dispatched by touching the screen. The <code>pointer</code> variable will contain the information about the pointer that activated the event.</p>

<p>This approach uses the generally available <code>this.game.input</code> object, but you can also detect the actions on any game objects like sprites or buttons by using <code>onInputOver</code>, <code>onInputOut</code>, <code>onInputDown</code>, <code>onInputUp</code>, <code>onDragStart</code>, or <code>onDragStop</code>:</p>

<pre class="brush: js">
this.button.events.onInputOver.add(itemTouched, this);

function itemTouched(button, pointer) {
    // do something
}</pre>

<p>That way you'll be able to attach an event to any object in the game, like the player's ship, and react to the actions performed by the user.</p>

<p>An additional advantage of using Phaser is that the buttons you create will take any type of input, whether it's a touch on mobile or a click on desktop — the framework sorts this out in the background for you.</p>

<h3 id="Implementation">Implementation</h3>

<p>The easiest way to add an interactive object that will listen for user input is to create a button:</p>

<pre class="brush: js">
var buttonEnclave = this.add.button(10, 10, 'logo-enclave', this.clickEnclave, this);</pre>

<p>This one is created in the <code>MainMenu</code> state — it will be placed ten pixels from the top left corner of the screen, use the <code>logo-enclave</code> image, and execute the <code>clickEnclave()</code> function when it is touched. This will work on mobile and desktop out of the box. There are a few buttons in the main menu, including the one that will actually start the game.</p>

<p>For the actual gameplay, instead of creating more buttons and covering the small mobile screen with them, we can use something a little bit different: we'll create invisible areas which respond to the given action. From a design point of view it is better to make the area of action bigger without covering half of the screen with button images. For example, tapping on the right side of the screen will fire the weapon:</p>

<pre class="brush: js">
this.buttonShoot = this.add.button(this.world.width*0.5, 0, 'button-alpha', null, this);
this.buttonShoot.onInputDown.add(this.goShootPressed, this);
this.buttonShoot.onInputUp.add(this.goShootReleased, this);</pre>

<p>The code above will create a new button using a transparent image that covers the right half of the screen. You can assign functions on input down and input up separately if you'd like to perform more complicated actions, but in this game touching the right side of the screen will simply fire the bullets to the right — this is all we need in this case.</p>

<p>Moving the player could be managed by creating the four directional buttons, but we can take the advantage of touch screens and drag the player's ship around:</p>

<pre class="brush: js">
var player = this.game.add.sprite(30, 30, 'ship');
player.inputEnabled = true;
player.input.enableDrag();
player.events.onDragStart.add(onDragStart, this);
player.events.onDragStop.add(onDragStop, this);

function onDragStart(sprite, pointer) {
    // do something when dragging
}</pre>

<p>We can drag the ship around and do something in the meantime, and react when the drag is stopped.</p>

<h3 id="Dedicated_plugins">Dedicated plugins</h3>

<p>You could go even further and use dedicated plugins like <a href="https://phaser.io/shop/plugins/virtualjoystick">Virtual Joystick</a> — this is a paid, official Phaser plugin, but you can find free and <a href="https://github.com/Gamegur-us/phaser-touch-control-plugin">open source alternatives</a>. The initialization of Virtual Joystick looks like this:</p>

<pre class="brush: js">
this.pad = this.game.plugins.add(Phaser.VirtualJoystick);
this.stick = this.pad.addStick(30, 30, 80, 'generic');</pre>

<p>In the <code>create()</code> function of the <code>Game</code> state we're creating a virtual pad and a generic stick that has four directional virtual buttons by default. This is placed 30 pixels from the top and left edges of the screen and is 80 pixels wide.</p>

<p>The stick being pressed can be handled during the gameplay in the <code>update</code> function like so:</p>

<pre class="brush: js">
if(this.stick.isDown) {
    // move the player
}</pre>

<p>We can adjust the player's velocity based on the current angle of the stick and move him appropriately.</p>

<h2 id="Summary">Summary</h2>

<p>That covers adding touch controls for mobile; in the next article we'll see how to add keyboard and mouse support.</p>

<p>{{NextMenu("Games/Techniques/Control_mechanisms/Desktop_with_mouse_and_keyboard", "Games/Techniques/Control_mechanisms")}}</p>
Revert to this revision