HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptModerate

First HTML5 game: Snake

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
gamefirsthtml5snake

Problem

Here's my first HTML5 game: a really simple snake. I've never made a game before and haven't had too much experience with JavaScript.

Fiddle



`$(document).ready(function(){

// SNAKE SETTINGS
var SQR_SIZE = 10;
var FRAMES = 100;

// SNAKE VARIABLES
var snakeSpeed = 50;
var moveCount = 0;
var snakeDirection = 38; //37 - left; 38 - up; 39 - right; 40 - down;

// OTHER VARS
var score = 0;

// TRAIL VARS
var xTrail = new Array();
var yTrail = new Array();
var snakeSize = 0;

// CREATE CANVAS
var c= document.getElementById("snakePlatform");
var ctx=c.getContext("2d");
var canvWidth = c.width;
var canvHeight = c.height;

c.addEventListener('click',function(e){mouseHandle(e.offsetX,e.offsetY);},false);

// SNAKE POSITIONING;
var xSnake;
var ySnake;
var xpos;
var ypos;
resetPositions();

// FOOD POSITIONING
var xFood;
var yFood;

// BUTTON POSITIONS
var buttonPos = new Array();

// GAMESTATE
var gameState = 0;
var preState = gameState;

// ----------- GAME PLAY -----------------------------------------------------------------

menuStart();

var checkGs=self.setInterval(function(){checkGamestate(gameState)},20);

function checkGamestate(s){
if(gameState != preState){
switch(s)
{
case 0:
menuStart();
preState = 0;
break;
case 1:
gameStart();
preState = 1;
break;
case 2:
pgStart();
preState = 2;
break;
default:
};
};
};

// ----------- GAME FUNCTIONS ------------------------------------------------------------

// GAME FLOW
function gameStart(){
var int=self.setInterval(function(){snakeAnimation()},snakeSpeed);

function snakeAnimation(){
i

Solution

It's pretty good for a first game. There are a few things I would change:

  1. Dependencies



You use jQuery for two purposes in your code: $(document).ready to trigger the game setup, and $(document).keydown to catch the keyboard events.

However, there really isn't any need to use jQuery for either of these things, so all it does is add to the load time of the page.

You can get rid of the $(document).ready completely if you move the JavaScript down to the bottom of the page (instead of inside the `).

You can replace
$(document).keydown(function(event){ with document.addEventListener('keydown',function(event){.

  1. Objects Namespaces



If you create a single component that uses a lot of JavaScript code, it is often considered best practice to put the code into an object. The biggest benefits of doing this are:

  • You don't have to worry about other things on the same page conflicting with this code because you (or someone else) gave them the same names. This is particularly important given that some of your variable names c, ctx, etc. are fairly generic and likely to be used again.



-
You can reuse the same code again and again to create multiple objects on the page without worrying about them interfering with each other. For example, you could create two snake games on a page by doing this:


    var snake1 = new Snake('snakePlatform1');
    var snake2 = new Snake('snakePlatform2');


Important Note: The code, as it exists now, will not work with more than one snake because it binds the
keydown event to the document and this would cause the keystrokes to be sent to both games at once. In order to use more than one, you will need to figure out how to "focus" one or the other snake game at a time for keyboard input. Explaining how to do this is beyond the scope of this answer.

-
You can expose some of the functionality of the snake game to outside code in a consistent and documented way. For example, you could provide a
getScore() method that returns the current score (or a snake.scored event that fires whenever the score changes), a turn(direction) method that allows outside control of the snake, etc. These would be accessed in the example above by calling snake1.getScore(), snake2.turn('DOWN'), etc. You might subscribe to the event using (a jQuery example) $('#snakePlatform1').on('snake.scored', function(score) {...}). The possibilities are endless.

It is also best to put this object inside a namespace. For example, instead of calling
new Snake('snakePlatform'), you would call new Dominic.Games.Snake('snakePlatform'). This makes it easier to track and maintain code in large projects. While this project is fairly simple and may not need namespaces, it's good to get in the habit of using them unless there is a very good reason not to do so.

  1. Enums



Although JavaScript doesn't really have the concept of
enum like many other languages, it is often useful to define helper objects that act as enums. Here are the two enums that I would define for this game:

var directions = {
    LEFT: 37,
    UP: 38,
    RIGHT: 39,
    DOWN: 40,
};

var states = {
    READY: 0,
    RUNNING: 1,
    OVER: 2,
};


This makes it much easier to see what parts of the code are doing, and therefore makes the code much easier to maintain. For instance, if you don't touch the code for a long time, then come back to it to make some changes, you don't have to relearn what the different numbers you used stand for.

I made a jsFiddle with these changes in it at http://jsfiddle.net/PXMAh/. Each of the sections above is done as a version of the fiddle, so you can add the version number at the end of the URL (last one is
...PXMAh/2/, back to .../1/ or .../0/`) to see the changes.

Code Snippets

<canvas id="snakePlatform1" width="400" height="400"></canvas>
<canvas id="snakePlatform2" width="400" height="400"></canvas>
<script>
    var snake1 = new Snake('snakePlatform1');
    var snake2 = new Snake('snakePlatform2');
</script>
var directions = {
    LEFT: 37,
    UP: 38,
    RIGHT: 39,
    DOWN: 40,
};

var states = {
    READY: 0,
    RUNNING: 1,
    OVER: 2,
};

Context

StackExchange Code Review Q#31919, answer score: 17

Revisions (0)

No revisions yet.