Snake Game

Screen drawing methods

We now add our drawing functions. We make use of a main function, that handles updates, clearing the canvas, and calling the current screen drawing function, and a seperate drawing function for each of the 2 game screens (menu and playing).

Firstly, our drawMenu function shows the "New Game" text, and current statistics, such as the best score, whether or not the player achieved a high score on their most recent game, and the score for the most recent game (if applicable).

function drawMenu()
	// Set the font for the main screen text
	ctx.textAlign	= "center";
	ctx.font	= "bold italic 20pt sans-serif";

	// Set the colour based on whether or not the moue cursor
	// is over the "New Game" text, then draw New Game
	ctx.fillStyle = ((mouseState.y>=150 && mouseState.y<=220) ?
		"#0000aa" : "#000000");
	ctx.fillText("New game", 150, 180);
	// Change the font and show the current best score
	ctx.font		= "italic 12pt sans-serif";
	ctx.fillText("Best score: " + gameState.bestScore, 150, 210);
		// If the player achieved a new top score during their
		// last game, say so
		ctx.fillText("New top score!", 150, 240);
		// If the player has just finished a game and scored any
		// points, then show the last score
		ctx.fillText("Last score: " + gameState.score, 150, 260);

Next, we have a method for drawing the game during play, drawPlaying. This shows the current score, the bounds of the map, the snakes body segments and the food.

function drawPlaying()
	// Set the stroke and fill colours
	ctx.strokeStyle = "#000000";
	ctx.fillStyle	= "#000000";
	// Draw the bouding area of the map
	ctx.strokeRect(offsetX, offsetY,
		(gameState.mapW * gameState.tileW),
		(gameState.mapH * gameState.tileH));
	for(var s in gameState.snake)
		// Loop through the snake body segments and draw each of them
		ctx.fillRect(offsetX + (gameState.snake[s][0] * gameState.tileW),
			offsetY + (gameState.snake[s][1] * gameState.tileH),
			gameState.tileW, gameState.tileH);
	// Set the font for the current score and show it
	ctx.font = "12pt sans-serif";
	ctx.textAlign = "right";
	ctx.fillText("Score: " + gameState.score, 290, 20);
	// Set the fill colour for the food, and draw it on the map
	ctx.fillStyle	= "#00cc00";
	ctx.fillRect(offsetX + (gameState.newBlock[0] * gameState.tileW),
		offsetY + (gameState.newBlock[1] * gameState.tileH),
		gameState.tileW, gameState.tileH);

Finally, we have the drawGame function. This not only calls the drawing method for the current screen and displays the frame rate if visibility is toggled on, but also calculates the current frame rate, the game time, and calls the updateGame function for managing the games logic:

function drawGame()
	if(ctx==null) { return; }
	// Frame & update related timing
	var currentFrameTime =;
	var timeElapsed = currentFrameTime - lastFrameTime;
	gameTime+= timeElapsed;
	// Update game

	// Frame counting
	var sec = Math.floor(;
		currentSecond = sec;
		framesLastSecond = frameCount;
		frameCount = 1;
	else { frameCount++; }
	// Clear canvas
	ctx.fillStyle = "#ddddee";
	ctx.fillRect(0, 0, 300, 400);

	// Set font and show framerate (if toggled)
		ctx.textAlign = "left";
		ctx.font = "10pt sans-serif";
		ctx.fillStyle = "#000000";
		ctx.fillText("Frames: " + framesLastSecond, 5, 15);
	// Draw the current screen
	if(gameState.screen=='menu')		{ drawMenu(); }
	else if(gameState.screen=='playing')	{ drawPlaying(); }
	// Update the lastFrameTime
	lastFrameTime = currentFrameTime;
	// Wait for the next frame...

Mouse position on Canvas element

We also have a helper method that converts the pageX, pageY values in the mouse event listeners of the window.onload method to the true position relative to the top left of the Canvas element.

This is required as positions are given relative to the top left of the document, so we need to find the offset of the Canvas relative to this position and subtract it to get the actual mouse position on the Canvas.

function realPos(x, y)
	var p = document.getElementById('game');
	do {
		x-= p.offsetLeft;
		y-= p.offsetTop;
		p = p.offsetParent;
	} while(p!=null);
	return [x, y];
Page loaded in 0.01 second(s).