Simple canvas game

Sometimes it can be difficult, for beginning developers to grasp the inner mechanics of a simple game. To help people understanding i created a very simple starting point for a canvas based game.

character-canvas

The code

You can download the code in this repo https://github.com/jeroenoliemans/canvasletter After downloading you can run “npm install” to install the dependencies and “webpack-dev-server” to run the code. By default the server will point to localhost:8080 .

First i will begin with a walkthrough of the code.The games consists of 2 classes the Character class is responsible for the character and the CharacterCanvas class is responsible for creating the Character instances, controlling these instances, stopping and starting the game and giving feedback over the scoring.

The Character

class Character {
    constructor() {
        this.characterX;
        this.characterY;
        this.characterChar;
        this.reset();
    }

    reset() {
        this.characterX = (Math.floor(Math.random()*(document.body.clientWidth)-30) + 15);
        this.characterY  = 0 - Math.floor(Math.random()*1000);
        this.characterChar = String.fromCharCode(97 + Math.floor(Math.random() * 26));
    }

    setyPos(newy) {
        this.characterY = newy 
    }
};
 
export default Character;

The Character has a reset method which moves the character back to the top on a random position if the user entered key matches the instances CharacterCode. The setY method is used, to position the Character instance from the CharacterCanvas class.

The CharacterCanvas

The CharacterCanvas has a few important methods:

  • createCanvas: creates the canvas and sets the defaults
  • createCharacters: this creates the Character instances and starts the game loop
  • startGameLoop: the actual game, which will be discussed in the next section

The game loop

startGameLoop() {
        this.clearCanvas();
        for(let i = 0; i < this.characters.length; i++) {
            let char = this.characters[i];
            this.ctx.font = '62px serif';
            this.ctx.fillText((char.characterChar).toString(), char.characterX, char.characterY);
            char.setyPos( char.characterY + this.velocity);

            // remove if off screen
            if( char.characterY > this.canvas.height ){
                this.characters.splice(i,1);
            }
        }
        
        // fontsize  for ui
        this.ctx.font = '36px serif';

        // start loop
        if(this.characters.length !== 0) {
            requestAnimationFrame(() => this.startGameLoop() );
        } else {
            this.isPlaying = false;
            this.ctx.fillText('GAME OVER', 50, 50);
            this.ctx.fillText('Hit space to restart', 50, 90);
            // write highscore
            if(this.score > this.getHighScore() ) {
                localStorage.setItem('textHighScore', this.score);
            }            
        }

        // display score
        this.ctx.fillText(`Score (${this.highScore.toString()}) : ` + (this.score).toString(), this.canvas.width - 250, this.canvas.height - 50);      
    }

This method clears the canvas,loops through all the available Character instances being hold in the this.characters array and updates their new position. If a character moves off screen than it is removed from the this.characters array. If there aren’t anymore characters left than the loop ends the game and displays ‘GAME OVER’.

The game is boring

It is, hence i kept the game to a bare minimum to improve fast understanding of the game mechanics. Nevertheless it is easy to make the game more interesting. We can improve the game or add the following features.

Create Levels

  • Multiply the velocity if the player reaches a score of 50, 100 ..
  • You can also use the modulus operator to create infinite levels

Add more difficult characters, with more speed and another color

  • Add a color property to the Character class
  • Add a velocityMultiplier property to the Character class, which defaults to 1
  • In the CharacterCanvas class multiply the velocity with the velocityMultiplier
  • Change the velocityMultiplier and the color of the Characters instances in the createCharacter method

What’s next

This game principle could be easily extended, with image sprites, to create a space invaders ore a tetris clone. And of course the code should be divided in more modules, for example modules for scoring, user events and configuration/constants.