Do you like my tutorials?

Then consider supporting me on Ko-fi

Talking about Game development, HTML5, Javascript, Phaser and TypeScript.

Adding a virtual joystick to your HTML5 games can be a hassle, or at least it could cost you some precious time, time you should spend doing the thing you love the most: developing games.

Luckily, here comes nippleJS, a library with no dependencies for touch capable interfaces, built by Yoann Moinet.

Although it has at lot of options, it’s incredibly straightforward, works perfectly even with all settings to their default values, and it can work both inside and outside HTML5 canvas.

Look at the example:

Touch/click and drag to make a virtual joystick appear and control the red square.

The canvas area of HTML5 game is the grey one, and as you can see you can invoke the joystick both inside and outside HTML5 area.

All you have to do, in your project, is to install nippleJS with npm:

npm install nipplejs --save

If you do not know what I am talking about, follow the tutorial about Working with Phaser, TypeScript and webpack step 1, 2 and 3.

Here is the source code, competely commented, consisting in one HTML file, one CSS file and four TypeScript files.

index.html

The web page which hosts the game, to be run inside thegame element.

<!DOCTYPE html>
<html>
    <head>
        <meta name="viewport" content="initial-scale=1, maximum-scale=1">
        <link rel="stylesheet" href="style.css">
        <script src="main.js"></script> 
    </head>
    <body>   
        <div id = "thegame"></div>
    </body>
</html>

style.css

The cascading style sheets of the main web page.

* {
    padding : 0;
    margin : 0;
}

body {
    background-color: #000000;    
}

canvas {
    touch-action : none;
    -ms-touch-action : none;
}

gameOptions.ts

Configurable game options. It’s a good practice to place all configurable game options, if possible, in a single and separate file, for a quick tuning of the game. I also grouped the variables to keep them more organized.

// CONFIGURABLE GAME OPTIONS
// changing these values will affect gameplay

export const GameOptions = {

    // max player speed, in pixels per second
    playerSpeed : 250
}

main.ts

This is where the game is created, with all Phaser related options.

// MAIN GAME FILE

// modules to import
import Phaser from 'phaser';
import { PreloadAssets } from './preloadAssets';
import { PlayGame } from './playGame';

// object to initialize the Scale Manager
const scaleObject : Phaser.Types.Core.ScaleConfig = {
    mode : Phaser.Scale.FIT,
    autoCenter : Phaser.Scale.CENTER_BOTH,
    parent : 'thegame',
    width : 600,
    height : 600
}

// game configuration object
const configObject : Phaser.Types.Core.GameConfig = {
    type : Phaser.AUTO,
    backgroundColor : 0x444444,
    scale : scaleObject,
    scene : [PreloadAssets, PlayGame],
    physics : {
        default : 'arcade',
        arcade : {
            gravity : {
                y : 0
            }
        }
    }
}

// the game itself
new Phaser.Game(configObject);

preloadAssets.ts

Here we preload all assets to be used in the game.

// CLASS TO PRELOAD ASSETS
 
// this class extends Scene class
export class PreloadAssets extends Phaser.Scene {
 
    // constructor    
    constructor() {
        super({
            key : 'PreloadAssets'
        });
    }
 
    // method to be called during class preloading
    preload() : void {

        // preload player sprite
        this.load.image('player', 'assets/sprites/player.png');
    }
 
    // method to be called once the instance has been created
    create() : void {

        // call PlayGame class
        this.scene.start('PlayGame');
    }
}

playGame.ts

Main game file, all game logic is stored here.

// THE GAME ITSELF

import nipplejs from 'nipplejs';
import { GameOptions } from './gameOptions';

// this class extends Scene class
export class PlayGame extends Phaser.Scene {

    constructor() {
        super({
            key : 'PlayGame'
        });
    }

    // the player
    player : Phaser.Physics.Arcade.Sprite;

    // method to be called once the instance has been created
    create() : void {

        // add player sprite, a physics sprite
        this.player = this.physics.add.sprite(this.game.config.width as number / 2, this.game.config.height as number / 2, 'player');  

        // create a joystick manager, leaving all default options
        let joystickManager : nipplejs.JoystickManager = nipplejs.create({});
        
        // listener to be triggered when the joystick moves
        joystickManager.on('move',  (data : nipplejs.EventData, output : nipplejs.JoystickOutputData) => {
            
            // get the force and don't let it be greater than 1
            let force : number = Math.min(output.force, 1);

            // get the angle, in radians
            let angle : number = output.angle.radian;

            // determine the speed, according to force and player speed
            let speed : number = GameOptions.playerSpeed * force;

            // set player velocity using trigonometry
            this.player.setVelocity(speed * Math.cos(angle), speed * Math.sin(angle) * -1);
        });

        // listener to be triggered when the joystick stops moving
        joystickManager.on('end',  () => {

            // stop the player
            this.player.setVelocity(0, 0);
        })
    }
}

And now we have a virtual joystick in just a bunch of lines. I will add more examples, meanwhile download the source code of the entire project.

Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.