Control your cross platform HTML5 game with keyboard, mouse or touch input with an all-in-one TypeScript code, powered by Phaser

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

When you develop cross platform HTML5 games, you have to keep in mind that a lot of people will play them using different systems: computers, tablets and smartphones, each one with is own control system.

Computer players will play with either keyboard or mouse, while mobile players will play using touch controls.

I am showing you how to handle, with only a single script, all possible input controls in a game controlled by left or right buttons, just like my Serious Scramblers prototype.

Look at the script in action:

You can control the “game”, which consinst in highlighting left and right halves of the canvas, with A or D keys, ARROW keys, Mouse or multitouch inputs.

If you have a mobile phone, you can access the result directly at this link or through this QRCode:

The example is built around one HTML and two TypeScript files, let’s see them in detail:

index.html

The webpage which hosts the game, just the bare bones of HTML.

Also look at the thegame div, this is where the game runs.

<!DOCTYPE html>
<html>
    <head>
        <script src = "main.js"></script>
    </head>
<body>
    <div id = "thegame"></div>
</body>
</html>

main.ts

The main TypeScript file, the one called by index.html.

Here we import most of the game libraries and define Scale Manager object.

Here we also initialize the game itself.

// MAIN GAME FILE

// modules to import
import Phaser from 'phaser';
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: 500,
    height: 500
}

// game configuration object
const configObject: Phaser.Types.Core.GameConfig = {
    type: Phaser.AUTO,
    scale: scaleObject,
    scene: [PlayGame]
}

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

playGame.ts

The core of the examples, in playGame class we make all stuff work and handle various types of user input

// THE GAME ITSELF

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

    // just a debug text to print some info
    debugText: Phaser.GameObjects.Text;

    arrowKeys: Phaser.Types.Input.Keyboard.CursorKeys;

    // variable to be assigned to keyboard key "A"
    keyA: Phaser.Input.Keyboard.Key;

    // variable to be assigned to keyboard key "B"
    keyD: Phaser.Input.Keyboard.Key;

    // flag to check if any left button has been pressed
    leftPressed: boolean;

    // flag to check if any right button has been pressed
    rightPressed: boolean;

    // flag to check if the mouse has been pressed
    mousePressed: boolean;

    // variable to store mouse X position
    mouseX: number;

    // left and right tilesprites to show highlighted directions
    leftHighlight: Phaser.GameObjects.TileSprite;
    rightHighlight: Phaser.GameObjects.TileSprite;

    // variable to quickly store game half width and height, as we are going to use them a lot of times
    halfGameWidth: number;
    gameHeight: number;

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

    // method to be called once the class preloads
    preload(): void {

        // load the dotted line image
        this.load.image('line', 'assets/dotted.png');

        // load highlight image
        this.load.image('highlight', 'assets/highlight.png');
    }

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

        // get half game width and height
        this.halfGameWidth = this.game.config.width as number / 2;
        this.gameHeight = this.game.config.height as number;

        // at the beginning of the game the mouse is not pressed
        this.mousePressed = false;

        // place left highlight tile sprite
        this.leftHighlight = this.add.tileSprite(0, 0, this.halfGameWidth, this.gameHeight, 'highlight');
        this.leftHighlight.setOrigin(0, 0);

        // place right highlight tile sprite
        this.rightHighlight = this.add.tileSprite(this.halfGameWidth, 0, this.halfGameWidth, this.gameHeight, 'highlight');
        this.rightHighlight.setOrigin(0, 0);

        // add the dotted line tilesprite and set its registration point
        this.add.tileSprite(this.halfGameWidth, 0, 4, this.gameHeight, 'line').setOrigin(0.5, 0);

        // initialize arrow keys
        this.arrowKeys = this.input.keyboard.createCursorKeys();

        // add to keyA keyboard input with "A" key
        this.keyA = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);

        // add to keyD keyboard input with "D" key
        this.keyD = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);

        // normally Phaser only handles one pointer, so we have to add one more pointer to handle multi touch
        this.input.addPointer(1);

        // mouse event listeners
        this.input.on('pointerdown', this.setMousePressed, this);
        this.input.on('pointerup', this.setMouseReleased, this);
        this.input.on('pointermove', this.getMousePosition, this);

        // just a debug text
        this.debugText = this.add.text(16, 16, '', {
            color: '#ffffff',
            fontFamily: 'monospace',
            fontSize: '18px'
        });
    }

    // method to be called when the mouse is pressed
    setMousePressed(pointer: Phaser.Input.Pointer): void {

        // mouse is pressed
        this.mousePressed = true;

        // save horizontal mouse position
        this.mouseX = pointer.x;
    }

    // method to be called when the mouse is released
    setMouseReleased(): void {

        // mouse is not pressed
        this.mousePressed = false;
    }

    // method to get mouse position
    getMousePosition(pointer: Phaser.Input.Pointer) {

        // save horizontal mouse position
        this.mouseX = pointer.x;
    }

    // method to be executed at each frame
    update(): void {

        // at the start of each frame, we assume both right and left buttons aren't pressed
        this.leftPressed = false;
        this.rightPressed = false;

        // report text to output at the end of the process
        let reportText: string = "";

        // is mouse pointer pressed
        if (this.mousePressed) {
            
            // is mouse pointer horizontal position greater than half the canvas width?
            if (this.mouseX > this.halfGameWidth) {

                // right button is being pressed
                this.rightPressed = true;

                // update report text
                reportText += "Mouse on right side\n";
            }
            else {

                // left button is being pressed
                this.leftPressed = true;

                // update report text
                reportText += "Mouse on left side\n";
            }
        }

        // is touch pointer1 down?
        if (this.input.pointer1.isDown) {

            // is pointer1 horizontal position greater than half the canvas width?
            if (this.input.pointer1.x > this.halfGameWidth) {

                // right button is being pressed
                this.rightPressed = true;

                // update report text
                reportText += "Pointer1 on right side\n";
            }
            else {

                // left button is being pressed
                this.leftPressed = true;

                // update report text
                reportText += "Pointer1 on left side\n";
            }
        }

        // is touch pointer2 down?
        if (this.input.pointer2.isDown) {

             // is pointer2 horizontal position greater than half the canvas width?
            if (this.input.pointer2.x > this.halfGameWidth) {

                // right button is being pressed
                this.rightPressed = true;

                // update report text
                reportText += "Pointer2 on right side\n";
            }
            else {

                // left button is being pressed
                this.leftPressed = true;

                // update report text
                reportText += "Pointer2 on left side\n";
            }
        }

        // is "A" key down?
        if (this.keyA.isDown) {

            // left button is being pressed
            this.leftPressed = true;

            // update report text
            reportText += "'A' key pressed\n";
        }

        // is "D" or key down?
        if (this.keyD.isDown) {
            
            // right button has been pressed
            this.rightPressed = true;

            // update report text
            reportText += "'D' key pressed\n";
        }

        // is left arrow key down?
        if (this.arrowKeys.left.isDown) {

            // left button is being pressed
            this.leftPressed = true;

            // update report text
            reportText += "'LEFT' key pressed\n";
        }

        // is right arrow key down?
        if (this.arrowKeys.right.isDown) {
            
            // right button has been pressed
            this.rightPressed = true;

            // update report text
            reportText += "'RIGHT' key pressed\n";
        }

        // make left highlight visible if left direction has been pressed
        this.leftHighlight.setVisible(this.leftPressed);

        // make right highlight visible if right direction has been pressed
        this.rightHighlight.setVisible(this.rightPressed);

        // prompt final result
        this.debugText.setText("Overall Left: " + this.leftPressed.toString() + "\nOverall Right: " + this.rightPressed.toString() + "\n-----------------\n" + reportText);
    }
}

This example only covers left and right input, with virtual buttons rather than virtual pads, but it’s quite easy to extend it and turn it into a virtual four movement multicontrol script. Download the source code.