Weekend Project: classic snake in plain Js

Written by eamonnmcevoy | Published 2018/06/10
Tech Story Tags: javascript | html5-games | web-development | programming | game-development

TLDRvia the TL;DR App

The classic game of snake makes a nice weekend project, this tutorial shows the game creates using html5 canvas. You can try the finished game a codepen, or check out the code on github

1. Render the game grid

basic grid render · eamonnmcevoy/snake@54395ca_Contribute to eamonnmcevoy/snake development by creating an account on GitHub._github.com

First step is simple, create an index.html to hold our canvas

index.html

<html><head></head><body><canvas id="game"></canvas><script src="./index.js"></script></body></html>

Now a Grid class to be responsible for rendering our game.

Simple code so far, this sets up our canvas object with a 2D context and renders a 50*50 grid of square that will form the play area of the game.

2. Update Grid with 2D array

create grid dataset · eamonnmcevoy/snake@525100e_Contribute to eamonnmcevoy/snake development by creating an account on GitHub._github.com

Before we add our snake object, the Grid class needs to be extended a bit. We will hold the grid state in a 2D array, this code will function as before but allow us to specify a ‘state’ for each cell, and colour it accordingly.

3. Create Snake class

create snake object · eamonnmcevoy/snake@ed6fa32_Contribute to eamonnmcevoy/snake development by creating an account on GitHub._github.com

Time to create our slithery hero, the snake! This class holds an array, parts, to represent the state of the snake. The update method will be responsible to update the position of the snake and return an array of cells that require updated on the grid, since we only have one cell for now the code is simple. The getter head returns a copy of the cell at the head of the snake.

4. Create Game class

create game object · eamonnmcevoy/snake@03b0de9_Contribute to eamonnmcevoy/snake development by creating an account on GitHub._github.com

In order to get our snake moving we need to create a game loop, responsible for updating the game state and coordinating our objects. All the action takes place in the run method, on each iteration of the game loop we render the grid, perform updates to the game state, and finally add a short delay (50ms) before running the next iteration.

`while(true)` . ¯\_( ⊙_ʖ⊙ )_/¯

5. Moving snake

move snake · eamonnmcevoy/snake@2b8a11e_Contribute to eamonnmcevoy/snake development by creating an account on GitHub._github.com

Now we are ready to do something interesting, make the snake move. For this stage we will simply move 1 cell to the right on each update. The Snakeupdate method is a bit more complex now. To move our snake we will calculate the new head position, the remove the ‘tail’ cell and put it in this new position.

isAlive tests for collisions with the edge of the board and with other cells on the snake.

Its alive!

6. Controlling snake

directional snake · eamonnmcevoy/snake@b03c629_Contribute to eamonnmcevoy/snake development by creating an account on GitHub._github.com

Now that our snake is on the move, we can start receiving keyboard input to control the direction of travel. The Game class now contains a handler method to process keyboard input, the arrow keys are bound to turn the snake up, down, left, or right. The snake has also been extended with an updatePosition method to determine the new position.

7. Optimize grid render

render optimization · eamonnmcevoy/snake@065c516_Contribute to eamonnmcevoy/snake development by creating an account on GitHub._github.com

There is a fairly bad inefficiency in the rendering of the game grid. On each iteration we redraw every cell, when we really only need to update cells that have changed since the last frame. This a simple change to make, the grid will hold an array of updatedCells, on calling setPoint we will push each point on to this array. Now we only need to redraw cells from this array, reducing the work of the render method from 2500 cells per frame to around 2–3, not a bad improvement for 4 lines of code.

8. Generate food

generate food · eamonnmcevoy/snake@e7c7001_Contribute to eamonnmcevoy/snake development by creating an account on GitHub._github.com

All this work is making me hungry, time to cook up some lunch for our scaly friend. Every 1 second, if there is no food on the grid, we will add one purple food cell at a random position.

9. Eat and grow

pickup food · eamonnmcevoy/snake@e513f98_Contribute to eamonnmcevoy/snake development by creating an account on GitHub._github.com

The final and most important element of gameplay, when the snake head collides with a food cell the snake should grow. In the main game loop we need to perform a simple check for collision with the food cell, if detected, remove the cell and grow the snake by one. To grow the snake, we add a new cell to the tail, in place of the previous tail position.

10. Track score

track score · eamonnmcevoy/snake@f1cf27b_Contribute to eamonnmcevoy/snake development by creating an account on GitHub._github.com

One final update to finish the game off, when a piece of food is collected, award 1 point. Simply add a score property to the Game class, increment when food is collected, display the score below the Canvas.

Hope you enjoyed this quick weekend project, if you would like more content like this give a few claps, or comments. Happy coding!


Published by HackerNoon on 2018/06/10