-1

I'm modifying a pre-written code to complete my project. It's a game where the snake eats the apple and grows. I need to replace the red blob which is an apple in the game with an image. I have included the code up to the part where the apple needs to be drawn since I could not upload the whole code. Let me know if you need the whole code.

<html>

<head>
  <title>IT105 Presentation</title>
  <style>
    html,
    body {
      height: 100%;
      margin: 0;
    }
    
    body {
      background: white;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    canvas {
      background-image: url(field.jpg);
      border: 1px solid black;
    }
  </style>
</head>

<body>
  <canvas width="400" height="400" id="game"></canvas>
  <script>
    var canvas = document.getElementById('game');
    var context = canvas.getContext('2d');

    var grid = 16;
    var count = 0;

    var snake = {
      x: 160,
      y: 160,

      // snake velocity. moves one grid length every frame in either the x or y direction
      dx: grid,
      dy: 0,

      // keep track of all grids the snake body occupies
      cells: [],

      // length of the snake. grows when eating an apple
      maxCells: 4
    };
    var apple = {
      x: 320,
      y: 320
    };

    // get random whole numbers in a specific range
    // @see https://stackoverflow.com/a/1527820/2124254
    function getRandomInt(min, max) {
      return Math.floor(Math.random() * (max - min)) + min;
    }

    // game loop
    function loop() {
      requestAnimationFrame(loop);

      // slow game loop to 15 fps instead of 60 (60/15 = 4)
      if (++count < 4) {
        return;
      }

      count = 0;
      context.clearRect(0, 0, canvas.width, canvas.height);

      // move snake by it's velocity
      snake.x += snake.dx;
      snake.y += snake.dy;

      // wrap snake position horizontally on edge of screen
      if (snake.x < 0) {
        snake.x = canvas.width - grid;
      } else if (snake.x >= canvas.width) {
        snake.x = 0;
      }

      // wrap snake position vertically on edge of screen
      if (snake.y < 0) {
        snake.y = canvas.height - grid;
      } else if (snake.y >= canvas.height) {
        snake.y = 0;
      }

      // keep track of where snake has been. front of the array is always the head
      snake.cells.unshift({
        x: snake.x,
        y: snake.y
      });

      // remove cells as we move away from them
      if (snake.cells.length > snake.maxCells) {
        snake.cells.pop();
      }

      // draw apple
      context.fillStyle = 'red';
      context.fillRect(apple.x, apple.y, grid - 1, grid - 1);

      // draw snake one cell at a time
      context.fillStyle = 'gold';
      snake.cells.forEach(function(cell, index) {

        // drawing 1 px smaller than the grid creates a grid effect in the snake body so you can see how long it is
        context.fillRect(cell.x, cell.y, grid - 1, grid - 1);

        // snake ate apple
        if (cell.x === apple.x && cell.y === apple.y) {
          snake.maxCells++;

          // canvas is 400x400 which is 25x25 grids 
          apple.x = getRandomInt(0, 25) * grid;
          apple.y = getRandomInt(0, 25) * grid;
        }

        // check collision with all cells after this one (modified bubble sort)
        for (var i = index + 1; i < snake.cells.length; i++) {

          // snake occupies same space as a body part. reset game
          if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) {
            snake.x = 160;
            snake.y = 160;
            snake.cells = [];
            snake.maxCells = 4;
            snake.dx = grid;
            snake.dy = 0;

            apple.x = getRandomInt(0, 25) * grid;
            apple.y = getRandomInt(0, 25) * grid;
          }
        }
      });
    }

    // listen to keyboard events to move the snake
    document.addEventListener('keydown', function(e) {
      // prevent snake from backtracking on itself by checking that it's 
      // not already moving on the same axis (pressing left while moving
      // left won't do anything, and pressing right while moving left
      // shouldn't let you collide with your own body)

      // left arrow key
      if (e.which === 37 && snake.dx === 0) {
        snake.dx = -grid;
        snake.dy = 0;
      }
      // up arrow key
      else if (e.which === 38 && snake.dy === 0) {
        snake.dy = -grid;
        snake.dx = 0;
      }
      // right arrow key
      else if (e.which === 39 && snake.dx === 0) {
        snake.dx = grid;
        snake.dy = 0;
      }
      // down arrow key
      else if (e.which === 40 && snake.dy === 0) {
        snake.dy = grid;
        snake.dx = 0;
      }
    });

    // start the game
    requestAnimationFrame(loop);
  </script>
</body>

</html>

1 Answers1

1

I believe what you're looking for is the JS function drawImage().

Currently you're implementing fillRect() of the form context.fillRect(x,y,width,height); to draw an "Apple" and then you're setting the fill color to "Red".

Using the variables for x, y, width, height that you already have you can make the image the same size as the "Apple" was if you desire, the values corresponding to the formula context.fillRect(x,y,width,height); are:

  • x : apple.x
  • y : apple.y
  • width : grid-1
  • height : grid-1

Essentially, implement this function of drawImage of the form void ctx.drawImage(image, dx, dy, dWidth, dHeight); as per CanvasRenderingContext2D.drawImage().

So your Draw Apple section would change from this:

**// draw apple**
  context.fillStyle='red';
  context.fillRect(apple.x, apple.y, grid-1, grid-1);

To this:

**// draw apple -- or use image in place of apple**
  const img = new Image();
  img.src = 'http://writingexercises.co.uk/images2/randomimage/restaurant-view.jpg';
  context.drawImage(img, apple.x, apple.y, grid-1, grid-1);

It's difficult for me to to test this solution as I've not got the full-code or any imported files you may be referencing, but this should give you a guide on how to proceed.

Also see my references:

CanvasRenderingContext2D.drawImage()

How would I fillRect with an image?

HTML canvas fillRect() Method

<html>
<head>
  <title>IT105 Presentation</title>
  <style>
  html, body {
    height: 100%;
    margin: 0;
  }

  body {
    background: white;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  canvas {
 background-image: url(field.jpg);
    border: 1px solid black;
  }
  </style>
</head>
<body>
<canvas width="400" height="400" id="game"></canvas>
<script>
var canvas = document.getElementById('game');
var context = canvas.getContext('2d');

var grid = 16;
var count = 0;
  
var snake = {
  x: 160,
  y: 160,
  
  **// snake velocity. moves one grid length every frame in either the x or y direction**
  dx: grid,
  dy: 0,
  
  **// keep track of all grids the snake body occupies**
  cells: [],
  
  **// length of the snake. grows when eating an apple**
  maxCells: 4
};
var apple = {
  x: 320,
  y: 320
};

**// get random whole numbers in a specific range**
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

**// game loop**
function loop() {
  requestAnimationFrame(loop);

  **// slow game loop to 15 fps instead of 60 (60/15 = 4)**
  if (++count < 4) {
    return;
  }

  count = 0;
  context.clearRect(0,0,canvas.width,canvas.height);

  **// move snake by it's velocity**
  snake.x += snake.dx;
  snake.y += snake.dy;

  **// wrap snake position horizontally on edge of screen**
  if (snake.x < 0) {
    snake.x = canvas.width - grid;
  }
  else if (snake.x >= canvas.width) {
    snake.x = 0;
  }
  
  **// wrap snake position vertically on edge of screen**
  if (snake.y < 0) {
    snake.y = canvas.height - grid;
  }
  else if (snake.y >= canvas.height) {
    snake.y = 0;
  }

  **// keep track of where snake has been. front of the array is always the head**
  snake.cells.unshift({x: snake.x, y: snake.y});

  **// remove cells as we move away from them**
  if (snake.cells.length > snake.maxCells) {
    snake.cells.pop();
  }

  **// draw apple -- or use image in place of apple**
  const img = new Image();
  img.src = 'http://writingexercises.co.uk/images2/randomimage/restaurant-view.jpg';
  context.drawImage(img, apple.x, apple.y, grid-1, grid-1);

  **// draw snake one cell at a time**
  context.fillStyle = 'gold';
  snake.cells.forEach(function(cell, index) {
    

Let me know how you get on!

EGC
  • 1,719
  • 1
  • 9
  • 20
  • i just included the whole code. i would really appreciate your assistance. – Mateshan Subramaniam Dec 04 '19 at 02:10
  • the apple does not appear at all if i use your code. – Mateshan Subramaniam Dec 04 '19 at 02:17
  • Please see the [JSFiddle](https://jsfiddle.net/jg0ckdbe/) where you can see that my code is working correctly – EGC Dec 04 '19 at 02:19
  • The intention described in your question suggests you don't _want_ the apple to appear, instead want an image to appear where the apple _was_. If you see the JSFiddle & my answer, you'll notice there is no apple, but instead an image where the apple _was_ as per your question. – EGC Dec 04 '19 at 02:22
  • everything's running fine but the the image (instead of the apple) won't appear – Mateshan Subramaniam Dec 04 '19 at 02:22
  • Did you see the [JSFiddle](https://jsfiddle.net/jg0ckdbe/) where it is working? Please check your console for errors, you may be referencing an image that doesn't exist (locally) or your setup won't allow you to access the referenced image. – EGC Dec 04 '19 at 02:23