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.
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.