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.