Snake Game Programming Fundamentals
Introduction
In this lesson weβll use the Snake game code to learn:
- Variables & Constants β where the game keeps its stuff
- Functions β little helpers that do one job
- Conditionals β βif this, then thatβ and switch
- Loops β doing things again and again
- Arrays & Objects β how we store the snake and the food
Weβll point to the exact lines/ideas in your code and give tiny experiments you can try.
Variables & Constants
Think of constants as labels for things that donβt change (like screen IDs or block size), and variables as boxes that can change (like score or snake direction).
// CONSTANTS (names in ALL_CAPS by convention)
const BLOCK = 10; // one grid square is 10x10 pixels
const SCREEN_SNAKE = 0; // play screen
const SCREEN_MENU = -1;
const SCREEN_GAME_OVER = 1;
const SCREEN_SETTING = 2;
// HTML elements / canvas
const canvas = document.getElementById("snake");
const ctx = canvas.getContext("2d");
// Game state VARIABLES (these change while you play)
let SCREEN = SCREEN_MENU;
let snake; // array of pieces
let snake_dir; // current direction (0 up, 1 right, 2 down, 3 left)
let snake_next_dir; // the direction we will turn to next
let snake_speed; // how fast the loop runs (ms)
let food = {x: 0, y: 0};// object with x,y
let score; // number
let wall; // 1 = on, 0 = off
Try it!
Change the board zoom by tweaking BLOCK
. Bigger number = bigger chunky snake.
Start faster by calling setSnakeSpeed(75)
instead of 150
in window.onload
.
Functions: keeping code tidy
Functions are verbs. Each one does one job. Snakeβs functions include:
Function | What it does |
---|---|
showScreen |
Shows the right screen (menu / game / settings / over) |
mainLoop |
Moves the snake, checks collisions, draws the frame |
newGame |
Resets the game to the starting state |
changeDir |
Handles arrow key presses |
activeDot |
Draws one square on the canvas |
addFood |
Picks a random empty spot for food |
checkBlock |
Tests if two grid spots are the same |
altScore |
Updates the score text |
setSnakeSpeed |
Sets how fast the game ticks |
setWall |
Turns wall wrap on/off and changes border color |
Callmap of Functions
window.onload
ββ sets up buttons, settings, key listener for Space
ββ (Space) β newGame
ββ showScreen(SCREEN_SNAKE)
ββ reset snake/score/food
ββ canvas.onkeydown β changeDir
ββ mainLoop (repeats forever with setTimeout)
ββ move snake head
ββ (if walls) game over when leaving canvas
ββ (if no walls) wrap around edges
ββ check snake hits itself β game over
ββ check eat food β grow, score++, addFood
ββ draw background, snake, food
ββ setTimeout(mainLoop, snake_speed)
Conditionals: βif this, then thatβ + switch
Direction control with a switch:
// 0 up, 1 right, 2 down, 3 left
switch(snake_dir){
case 0: _y--; break;
case 1: _x++; break;
case 2: _y++; break;
case 3: _x--; break;
}
Key presses with a switch + safety checks:
switch(key) {
case 37: if (snake_dir !== 1) snake_next_dir = 3; break; // left
case 38: if (snake_dir !== 2) snake_next_dir = 0; break; // up
case 39: if (snake_dir !== 3) snake_next_dir = 1; break; // right
case 40: if (snake_dir !== 0) snake_next_dir = 2; break; // down
}
The if checks prevent instant 180Β° turns (which would crash into your own neck).
Collision checks with if:
// Walls on? Out of bounds = game over
if (wall === 1) {
if (snake[0].x < 0 || snake[0].x === canvas.width / BLOCK ||
snake[0].y < 0 || snake[0].y === canvas.height / BLOCK) {
showScreen(SCREEN_GAME_OVER);
return;
}
}
Try it!
Add a bonus: if score is a multiple of 5, speed up a little.
Loops: do it again (and again)
The game βloopβ is a function (mainLoop) that calls itself again later using setTimeout(β¦). Thatβs how animation happens.
// at the end of mainLoop
setTimeout(mainLoop, snake_speed);
for
loops in the game!
Wrap-around when walls are off:
for (let i = 0; i < snake.length; i++) {
// fix x and y to wrap across edges
}
Self-collision check:
for (let i = 1; i < snake.length; i++) {
if (snake[0].x === snake[i].x && snake[0].y === snake[i].y) { /* game over */ }
}
Draw every segment:
for (let i = 0; i < snake.length; i++){
activeDot(snake[i].x, snake[i].y);
}
Event listener setup (looping over radio buttons):
for (let i = 0; i < speed_setting.length; i++){
speed_setting[i].addEventListener("click", function(){ /* ... */ });
}
Try it!
Make the snake start longer: after snake.push({x: 0, y: 15});, add a tiny loop to add two more pieces.
Arrays & Objects
Snake = array of objects
Each body part is an object with {x, y}
. All parts together form an array in order from head to tail.
snake = [];
snake.push({x: 0, y: 15}); // head at start
// laterβ¦
snake.unshift({x: _x, y: _y}); // add new head
snake.pop(); // remove tail
unshift
puts an item at the start of the array (index 0).
pop
removes the last item. This creates the βmovingβ effect.
Food: A Single Object:
let food = { x: 0, y: 0 };
function addFood(){
food.x = Math.floor(Math.random() * ((canvas.width / BLOCK) - 1));
food.y = Math.floor(Math.random() * ((canvas.height / BLOCK) - 1));
// if food lands on the snake, try again
for (let i = 0; i < snake.length; i++){
if (checkBlock(food.x, food.y, snake[i].x, snake[i].y)) {
addFood(); // recursion retry
}
}
}
Try it!
Give the food a βspecial modeβ every 7 points
Quick Recap
- Variables/Constants keep track of game state and fixed labels.
- Functions break the game into clear jobs.
- Conditionals decide what happens (turns, walls, collisions).
- Loops repeat drawing, checking, and event setup.
- Arrays/Objects store the snake body and food neatly.
Congrats on finishing the lesson! You are now ready to make your own variations on the Snake game.
π Quick Check
What did you learn?