
The game snake as a concept dates back to a 1976 arcade game called “Blockade” in which multiple players each controlled a “snake” (though it was never referred to as such in “Blockade”) and tried to avoid hitting objects or other players on the screen. “Blockade” ended up being quite the popular title which inspired lots of people to make copy cat versions of it almost immediately. Atari released a few different variants of the game on their consoles and it eventually found its way onto the PC too. The game had a huge surge in popularity after Nokia began to pre load it on their phones starting in 1998 and to this day the Nokia Phone version of snake is one of the most well known games around.
Its possible to make your own snake clone with just native JavaScript but it’ll be a pain to do and probably pretty clunky as well so you should really use a library instead. There are dozens upon dozens of different libraries for making JavaScript games and I’ve decided to go with Phaser for this project. Phaser is by no means the greatest or most powerful gaming library around for JavaScript but I’ve chosen to go with it because it’s clean and easy to use which I think is fitting for a beginners project like snake.
Go here to download Phaser and here if you want to read the documentation available on it.
Something to note before getting started is that JavaScript programs with the Phaser library only run when they’re on a server. Setting up a basic web server for yourself is fairly easy to do and you can read more about some of the different ways of doing it here.
Here’s what our final product’s going to look like:
Initial Steps
After you’ve gotten the library and set up a web server you should also go ahead and download the assets I’ve made for this project which include a start menu, a game over screen and sprites for the snake and fruit as well.
Before going on and creating your main HTML document you should also set up a folder for all of the JavaScript files that you’re going to need. Along with the library itself which you should already have we’ll be creating the following JavaScript files: One for the main menu, one for the game itself, one for the game over screen and one last one which will act as a sort of start point for the program where the window is made and the various game scenes/states are added in.
Now that you have all of the necessary prerequisites set up you start creating the HTML portion of the program. Start out with just a standard HTML document setup: A doc type declaration, a head element , a HTML element and finally a body element.
<!DOCTYPE html> <html> <head> </head> <body> </body> </html>
Once you’ve got the document set up you should add links to all of the JavaScript files that I mentioned you’d need to prepare earlier.
<script src="js/phaser.min.js"></script> <script src="js/menu.js"></script> <script src="js/game.js"></script> <script src="js/game_over.js"></script> <script src="js/main.js"></script>
Also in the head I’d recommend you include the following style tag as well:
<style> canvas{ margin: 0 auto; padding-top: 10px; } </style>
The library will draw the game onto its own canvas element and this piece of styling just ensures that it will be centred since by default the game screen appears at the top left side. There is code in the Phaser library that will allow you to centre the game window automatically, but when that methods used you can clearly see the window move from the left side to the centre on page load which isn’t a problem if you just use the styling.
The Main File
Hop into the main js file that you made earlier and create a new variable called game, this is what’s going to represent the game window in the program. Next set this variable equal to a new instance of a Phaser game window using the following function:
game = new Phaser.Game(640, 400, Phaser.AUTO, ''); //Creates Game Window
The first two arguments you see there represent the width and height values of the window. After that is the setting for how the window should be drawn which I’ve just set to the default for this program. Finally there’s also the name of the element you want to load the window into which I’ve left blank for this as I don’t want it loading into any other canvas’s or divs.
Next we need to add all of the different states we’ll be making to the game. In Phaser a state is in essence just one scene of a game such as the main menu screen or the game over screen. Our game is going to have the following three states: a main menu, the game itself,and a game over screen. You can add these states using the “game.state.add(‘tite’, state)” function.
game.state.add('Menu',Menu); //Adds Menu State game.state.add('Game', Game); //Adds Game State game.state.add('Game_Over', Game_Over); //Adds Game Over State
Lastly you should use the “game.state.start(state)” function, this will cause the main menu to appear automatically every time.
game.state.start('Menu'); //Starts Menu State
Main Menu
Once you’ve opened up your file for the main menu you should start by creating a new variable that has the same name as whatever you decided to name the menu state in the last section. This variable is going to contain everything in the scene and is what the “add()” and “start() functions are both directly calling on in your main file.
[codelanguage=”javascript”]
var Menu = {
[/code]
Inside this variable you’re going to want to set up a function called “preload”. This is part of the Phaser library and everything that happens inside “preload” is done before the game window is loaded in. Within “preload” you should use “game.load.image(“imgtitle”, “imgpath”) to add in whatever sprite you’re using to represent the main menu.
preload : function() { game.load.image('start', './img/start.png'); //Loads in Main Menu Image },
Next you should put in a call to the “create” function, this is similar to “preload” except that it’s called after the game window has already been created. In here you can use “this.add.button()” to turn your menu image into a button that runs a function to start the game.
create: function () { this.add.button(0, 0, 'start', this.game, this); //Turns Main MenuImage into a button },
The first two variables there are the x and y positions of the button, next is the name of loaded image that you want to represent the button, after that is the function the button should trigger when pressed and last is the game state the button should be loaded into.
Finally we have to actually create the function that starts the game itself. Inside it use the same Phaser function that we used for triggering the menu in the last section except swap out the “Menu” variable for “Game” instead and use “this” instead of “game” at the start of the function call.
game: function () { this.state.start('Game'); //Starts the Game }
Setting up the Game
Now its time to go ahead and set up the game itself. Before you create the variable for the “Game” state you should declare the following variables first:
var snake, fruit, grid, score, speed, updateDelay, direction, new_direction, addNew, keyControls, scoreTextValue, speedTextValue, textStyle_Key, textStyle_Value;
These variables are going to be accessed across multiple functions and so they needed to be made global by being declared before anything else in the file.
After this you should actually create the “Game” state variable and inside it have a “preload” function that loads in your sprites for the snake and the fruit.
var Game = { preload : function() { game.load.image('snake', './img/snake.png'); game.load.image('fruit', './img/fruit.png'); },
Next you need to call the create function and in there begin defining all the global variables you made at the start of the file. Your snake variable should be set to an empty array, fruit should be an empty object literal, grid should equal the size of the snake sprite your using which is 15 in my case, score, speed and update delay should all start at 0, the default the direction the snake should be moving is to the right, new_direction should be null since no keys have been pressed yet and finally addNew should be set to false.
create : function() { snake = []; //Represents the Snake fruit = {}; //Fruit Pickup object grid = 15; //Size of one grid square, should be equal to size of one snake square score = 0; //Player Score speed = 0; //Snake Speed updateDelay = 0; //How often update() is run direction = 'right'; //Current Direction snake is moving new_direction = null; // New Direction of snake addNew = false; //Determines if a new block should be added to the end of the snake
After this you need to use the “game.input.keyboard.createCursorKeys()” function so that way the game can accept input from the users arrow keys, to do this set the “keyControls” variable equal to the function I just mention.
keyControls = game.input.keyboard.createCursorKeys();
Now you should set the background colour using “game.stage.backgroundcolor = hexcode”, personally I’m going for a sort of retro lime green colour but pick whatever suits your fancy.
keyControls = game.input.keyboard.createCursorKeys();
Next you should use a for statement to generate your snake. Set the loop to iterate a number of times equal to how many blocks long you want the snake to be at the start (I recommend 10) and then inside it add a snake body part sprite to your “snake” array with the “game.add.sprite” function. In that function you need to set where you want each sprite to spawn so be sure to setup where they’re all on the same y position but are properly spread apart on the y axis.
for(var i = 0; i < 10; i++){ snake[i] = game.add.sprite(150+i*grid, 150, 'snake'); // Parameters are (X coordinate, Y coordinate, image) }
Later on we’ll be making a function that spawns in a fruit but the game should start with a piece of fruit already on the board so you should put a call to the function here even though you’ve not made it yet.
this.generatefruit();
The last thing you should do in the create function is put a display for the score in the top left-hand side of the screen. Create an object that contains the styling you want for the text and then use “game.add.text(x,y,text,text style”) to insert it into the game. You can display the variable for the score as text by using the method “.toString()” on it when you pass it into the add text function.
textStyle_Key = { font: "bold 14px sans-serif", fill: "#222222", align: "center" }; textStyle_Value = { font: "bold 18px sans-serif", fill: "#222222", align: "center" }; game.add.text(30, 20, "SCORE: ", textStyle_Key); scoreTextValue = game.add.text(90, 18, score.toString(), textStyle_Value);
The “update” function comes packaged with Phaser and is being constantly run in any program its a part of, the idea being that this is where you check to see if the player has moved, if the player is still alive and stuff of that nature. Your going to want to put this function inside your game js file and the first thing you should have in it is in fact a check to see if the player has changed direction since the last time the function was called.
update: function() { if (keyControls.right.isDown && direction!='left') { new_direction = 'right'; } else if (keyControls.left.isDown && direction!='right') { new_direction = 'left'; } else if (keyControls.up.isDown && direction!='down') { new_direction = 'up'; } else if (keyControls.down.isDown && direction!='up') { new_direction = 'down'; }
Next the current speed of the player needs to be checked. Speed should be dependent on how many points the player’s scored so far, I’ve set it to increase every three points scored but you can do more or less if you wish. Also there should be a maximum limit on how fast the snake can get to ensure the game doesn’t become impossible to play, you can do this with the “Math.min(max, num)” function from native JavaScript.
speed = Math.min(6, Math.floor(score/3)); new_direction = 'up'; }
Update by default runs far too often so we need to set a delay on how often the function actually updates the movement of the player, how often this happens should be dependent on the current speed of the player.
updateDelay++; if (updateDelay % (10 - speed) == 0) {
Next we need to have each piece of the snake shift in the correct direction when the player moves, use an if statement that detects current direction and then shifts each piece of the snake up one in the array that makes it up as this will cause it to move about the screen.
if (updateDelay % (10 - speed) == 0) { var firstCell = snake[snake.length - 1], lastCell = snake.shift(), oldLastCellx = lastCell.x, oldLastCelly = lastCell.y; if(new_direction) { direction = new_direction; new_direction = null; } if(direction == 'right') { lastCell.x = firstCell.x + 15; lastCell.y = firstCell.y; } else if(direction == 'left') { lastCell.x = firstCell.x - 15; lastCell.y = firstCell.y; } else if(direction == 'up') { lastCell.x = firstCell.x; lastCell.y = firstCell.y - 15; } else if(direction == 'down') { lastCell.x = firstCell.x; lastCell.y = firstCell.y + 15; } snake.push(lastCell); firstCell = lastCell;
After this we should check if the player has collided with a piece of fruit and if so add a number of new body cells to the end of the snake. How many pieces you want to be added upon each collection of fruit is up to you but I’ve personally gone with 3 here.
if(addNew) { snake.unshift(game.add.sprite(oldLastCellx, oldLastCelly, 'snake')); snake.unshift(game.add.sprite(oldLastCellx, oldLastCelly,'snake')); snake.unshift(game.add.sprite(oldLastCellx, oldLastCelly,'snake')); addNew = false; }
Finally at the end of the update function we need to check if the player has actually collided with a fruit, itself, or one of the game walls. We’ll be making the functions themselves in a moment but they need to be checked now so just insert the calls to them here.
this.fruitCollision(); this.selfCollision(firstCell); this.wallCollision(firstCell);
Before we detect for collision with the fruit though we should probably make the function that spawns one in first. Just add the appropriate sprite to the fruit object you created before and set it to spawn on a valid point on the board and your good.
generatefruit: function() { var randomX = Math.floor(Math.random() * 35) * grid, randomY = Math.floor(Math.random() * 25) * grid; fruit = game.add.sprite(randomX, randomY, 'fruit'); },
To detect if the player has collided with the fruit use a for statement to check if any of the snakes body parts are currently on the same square as the fruit. When the snake collides with the fruit the current fruit should be destroyed, a new fruit spawned, the players score should be increased and the size of the snake should be increased.
</pre> fruitCollision: function() { for(var i = 0; i < snake.length; i++) { if(snake[i].x == fruit.x &amp;amp;amp;amp;&amp;amp;amp;amp; snake[i].y == fruit.y) { addNew = true; fruit.destroy(); this.generatefruit(); score++; scoreTextValue.text = score.toString(); } } }
Next check to see if the snake has collided with itself and if it has have the game enter the “Game_Over” state.
selfCollision: function(head) { for(var i = 0; i < snake.length - 1; i++) { if(head.x == snake[i].x && head.y == snake[i].y) { game.state.start('Game_Over'); } } },
Lastly to check if the snake has collided with any of the walls merely check to see if it has moved to a location outside the bounds of the game window and if so have the game enter the “Game_Over” state.
wallCollision: function(head) { if(head.x > = 640 || head.x < 0 || head.y > = 400 || head.y < 0) { game.state.start('Game_Over'); } } };
Game Over Screen
The final thing you should do for your game is create a simple game over screen that appears whenever the player dies. Start off by creating the variable for the state and inside it insert a call to “preload” which loads in whatever image you’re using for the game over screen.
var Game_Over = { preload : function() { game.load.image('gameover', './img/gameover.png'); //Loads in Game Over Image },
After this make a call to “create” and turn the game over image into a clickable button which will allow the player to restart the game.
create : function() { this.add.button(0, 0, 'gameover', this.game, this); //Turns Game Over Image into Button
You should also display the user’s final score at the button so they know how well they did. Do this the same way you displayed the score during the game itself with the only difference being that the text should be a lot bigger and at the bottom centre of the screen instead of the top left.
game.add.text(235, 350, "FINAL SCORE: ", { font: "bold 16px sans-serif", fill: "#222222", align: "center"}); game.add.text(350, 348, score.toString(), { font: "bold 20px sans-serif", fill: "#222222", align: "center" }); //Displays Final Score
And finally just copy/paste the start game function you created for the main menu to this file and then the game is all finished!
game.stage.backgroundColor = '#9BBC0F';
Further Suggestions
The version of snake that we’ve made here is fairly bare bones with just the basic level type and no other difficulty options available. You could quite easily go ahead and add more game modes which have various obstacles dotted about or harder difficulty options where the snake grows more quickly and starts out moving faster. If you want a bit more of a challenge you could try adding a high score system that keeps track of the scores achieved across all the games played by every user.
Good Luck!
Download the source code here.
If you have any questions or comments email them to me at nick@crumbsofcode.com