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

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.

Get the most popular Phaser 3 book

Through 202 pages, 32 source code examples and an Android Studio project you will learn how to build cross platform HTML5 games and create a complete game along the way.

Get the book

215 GAME PROTOTYPES EXPLAINED WITH SOURCE CODE
// 1+2=3
// 100 rounds
// 10000000
// 2 Cars
// 2048
// A Blocky Christmas
// A Jumping Block
// A Life of Logic
// Angry Birds
// Angry Birds Space
// Artillery
// Astro-PANIC!
// Avoider
// Back to Square One
// Ball Game
// Ball vs Ball
// Ball: Revamped
// Balloon Invasion
// BallPusher
// Ballz
// Bar Balance
// Bejeweled
// Biggification
// Block it
// Blockage
// Bloons
// Boids
// Bombuzal
// Boom Dots
// Bouncing Ball
// Bouncing Ball 2
// Bouncy Light
// BoxHead
// Breakout
// Bricks
// Bubble Chaos
// Bubbles 2
// Card Game
// Castle Ramble
// Chronotron
// Circle Chain
// Circle Path
// Circle Race
// Circular endless runner
// Cirplosion
// CLOCKS - The Game
// Color Hit
// Color Jump
// ColorFill
// Columns
// Concentration
// Crossy Road
// Crush the Castle
// Cube Jump
// CubesOut
// Dash N Blast
// Dashy Panda
// Deflection
// Diamond Digger Saga
// Don't touch the spikes
// Dots
// Down The Mountain
// Drag and Match
// Draw Game
// Drop Wizard
// DROP'd
// Dudeski
// Dungeon Raid
// Educational Game
// Elasticity
// Endless Runner
// Erase Box
// Eskiv
// Farm Heroes Saga
// Filler
// Flappy Bird
// Fling
// Flipping Legend
// Floaty Light
// Fuse Ballz
// GearTaker
// Gem Sweeper
// Globe
// Goat Rider
// Gold Miner
// Grindstone
// GuessNext
// Helicopter
// Hero Emblems
// Hero Slide
// Hexagonal Tiles
// HookPod
// Hop Hop Hop Underwater
// Horizontal Endless Runner
// Hundreds
// Hungry Hero
// Hurry it's Christmas
// InkTd
// Iromeku
// Jet Set Willy
// Jigsaw Game
// Knife Hit
// Knightfall
// Legends of Runeterra
// Lep's World
// Line Rider
// Lumines
// Magick
// MagOrMin
// Mass Attack
// Math Game
// Maze
// Meeblings
// Memdot
// Metro Siberia Underground
// Mike Dangers
// Mikey Hooks
// Nano War
// Nodes
// o:anquan
// One Button Game
// One Tap RPG
// Ononmin
// Pacco
// Perfect Square!
// Perfectionism
// Phyballs
// Pixel Purge
// PixelField
// Planet Revenge
// Plants Vs Zombies
// Platform
// Platform game
// Plus+Plus
// Pocket Snap
// Poker
// Pool
// Pop the Lock
// Pop to Save
// Poux
// Pudi
// Pumpkin Story
// Puppet Bird
// Pyramids of Ra
// qomp
// Quick Switch
// Racing
// Radical
// Rebuild Chile
// Renju
// Rise Above
// Risky Road
// Roguelike
// Roly Poly
// Run Around
// Rush Hour
// SameGame
// SamePhysics
// Save the Totem
// Security
// Serious Scramblers
// Shrink it
// Sling
// Slingy
// Snowflakes
// Sokoban
// Space Checkers
// Space is Key
// Spellfall
// Spinny Gun
// Splitter
// Spring Ninja
// Sproing
// Stabilize!
// Stack
// Stairs
// Stick Hero
// String Avoider
// Stringy
// Sudoku
// Super Mario Bros
// Surfingers
// Survival Horror
// Talesworth Adventure
// Tetris
// The Impossible Line
// The Moops - Combos of Joy
// The Next Arrow
// Threes
// Tic Tac Toe
// Timberman
// Tiny Wings
// Tipsy Tower
// Toony
// Totem Destroyer
// Tower Defense
// Trick Shot
// Tunnelball
// Turn
// Turnellio
// TwinSpin
// vvvvvv
// Warp Shift
// Way of an Idea
// Whack a Creep
// Wheel of Fortune
// Where's my Water
// Wish Upon a Star
// Word Game
// Wordle
// Worms
// Yanga
// Yeah Bunny
// Zhed
// zNumbers