Lesson 12

Now that an apple appears on the screen, we can make eating it grow the snake.

To do that, we'll create a stationary copy of the snakes last segment. When the snake moves next the copied segment will stay in place, causing it to "grow" on the screen.

var growSnake = function(snake) {
  var indexOfLastSegment = snake.length - 1;
  var lastSegment = snake[indexOfLastSegment];
  snake.push({ top: lastSegment.top, left: lastSegment.left });
  return snake;
}

Now that we have a function to grow the snake, let's check for a collision between the apple and the snake whenever the game advances. Let's change the advanceGame function so it looks like this:

var advanceGame = function() {
  snake = moveSnake(snake);
  if (CHUNK.detectCollisionBetween([apple], snake)) {
    snake = growSnake(snake);
    apple = CHUNK.randomLocation();
  }
  if (CHUNK.detectCollisionBetween(snake, CHUNK.gameBoundaries())) {
    CHUNK.endGame();
    CHUNK.flashMessage("Whoops! you hit a wall!");
  }
  draw(snake, apple);
}

Expected Results

What your snake.js file should look like:

var draw = function(snakeToDraw, apple) {
  var drawableSnake = { color: "green", pixels: snakeToDraw };
  var drawableApple = { color: "red", pixels: [apple] };
  var drawableObjects = [drawableSnake, drawableApple];
  CHUNK.draw(drawableObjects);
}

var moveSegment = function(segment) {
  switch(segment.direction) {
    case "down":
      return { top: segment.top + 1, left: segment.left };
    case "up":
      return { top: segment.top - 1, left: segment.left };
    case "right":
      return { top: segment.top, left: segment.left + 1 }
    case "left":
      return { top: segment.top, left: segment.left - 1 }
    default:
      return segment;
  }
}

var segmentFurtherForwardThan = function(index, snake) {
  return snake[index - 1] || snake[index];
}

var moveSnake = function(snake) {
  return snake.map(function(oldSegment, segmentIndex) {
    var newSegment = moveSegment(oldSegment);
    newSegment.direction = segmentFurtherForwardThan(segmentIndex, snake).direction;
    return newSegment;
  });
}

var growSnake = function(snake) {
  var indexOfLastSegment = snake.length - 1;
  var lastSegment = snake[indexOfLastSegment];
  snake.push({ top: lastSegment.top, left: lastSegment.left });
  return snake;
}

var advanceGame = function() {
  snake = moveSnake(snake);
  if (CHUNK.detectCollisionBetween([apple], snake)) {
    snake = growSnake(snake);
    apple = CHUNK.randomLocation();
  }
  if (CHUNK.detectCollisionBetween(snake, CHUNK.gameBoundaries())) {
    CHUNK.endGame();
    CHUNK.flashMessage("Whoops! you hit a wall!");
  }
  draw(snake, apple);
}

var changeDirection = function(direction) {
  snake[0].direction = direction;
}

var apple = CHUNK.randomLocation();
var snake = [{ top: 1, left: 0, direction: "down" }, { top: 0, left: 0, direction: "down" }];

CHUNK.executeNTimesPerSecond(advanceGame, 1);
CHUNK.onArrowKey(changeDirection);

How the game should work so far:

Syntax Breakdown

array.length tells us how many elements are in a list. Arrays are zero indexed, so we subtract one to get the index of the last element in the list.

Play Time!

  • When is the newly added segment given a direction to move in?
  • Why do we put the apple variable inside of [] when we call detectCollision

Next Step: