Search code examples
javascripthtmlcanvas

Alternative to using an event in a setinterval


So I tried my code and I ain't getting the results I expect, especially with the function btnr. Basically what I'm trying to achieve is this: as the code is running I want the snake to change direction when the button is clicked.

var canvas = document.querySelector("canvas");
var right = document.querySelector("#right");
var left = document.querySelector("#left");
var up = document.querySelector("#up");
var down = document.querySelector("#down");

canvas.width = window.innerWidth;
canvas.height = window.innerHeight - 200;
var ctx = canvas.getContext("2d");

width = 20;
height = 20;

var snake = [{
  x: 40,
  y: 0
}, {
  x: 20,
  y: 0
}];

function move() {
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  for (var i = 0; i < snake.length; i++) {
    console.log(i);
    //lets just say i stands for index number
    ctx.strokeStyle = "orange";
    ctx.strokeRect(snake[i].x, snake[i].y, width, height);
  }

  snakex = snake[0].x;
  snakey = snake[0].y;
  snakex += 20;

  function btnr() {
    snakex -= 20;
  }
  right.addEventListener("click", btnr);

  var newhead = {
    x: snakex,
    y: snakey
  };
  snake.pop();
  snake.unshift(newhead);
}

setInterval(move, 800);
<canvas></canvas>
<button id="right">right</button>
<button id="down">down</button>
<button id="left">left</button>
<button id="up">up</button>


Solution

  • I've adjusted the code to make the buttons respond as you expect:

    const canvas = document.querySelector("canvas");
    const right = document.querySelector("#right");
    const left = document.querySelector("#left");
    const up = document.querySelector("#up");
    const down = document.querySelector("#down");
    
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight - 200;
    const ctx = canvas.getContext("2d");
    
    const width = 20;
    const height = 20;
    
    const snake = [{
      x: 40,
      y: 0
    }, {
      x: 20,
      y: 0
    }];
    
    // --- NEW --- //
    let direction = 'right'
    
    right.addEventListener("click", () => direction = 'right');
    left.addEventListener("click", () => direction = 'left');
    up.addEventListener("click", () => direction = 'up');
    down.addEventListener("click", () => direction = 'down');
    
    function move() {
      ctx.clearRect(0, 0, canvas.width, canvas.height)
      for (let i = 0; i < snake.length; i++) {
        //lets just say i stands for index number
        ctx.strokeStyle = "orange";
        ctx.strokeRect(snake[i].x, snake[i].y, width, height);
      }
    
      let snakex = snake[0].x;
      let snakey = snake[0].y;
    
      // --- NEW --- //
      if (direction === 'right') {
        snakex += 20;
      } else if (direction === 'left') {
        snakex -= 20;
      } else if (direction === 'up') {
        snakey -= 20;
      } else if (direction === 'down') {
        snakey += 20;
      }
    
      const newhead = {
        x: snakex,
        y: snakey
      };
    
      snake.pop();
      snake.unshift(newhead);
    }
    
    setInterval(move, 800);
    :root {
      background-color: #242424;
    }
    <div id="app">
      <canvas></canvas>
      <button id="right">right</button>
      <button id="down">down</button>
      <button id="left">left</button>
      <button id="up">up</button>
    </div>

    The main concept you were missing is that you need some way to to track what direction the snake is going. To do that, we can create a variable direction and set it to a string that represents the snake's direction.

    After that, we can hook up the buttons to change the direction when each button is pressed by setting the direction variable to left, right, up, or down depending on what was pressed. I moved the logic to add these handles out of your event loop because it would add a new handler each time, which is unnecessary.

    Finally in the event loop itself we have some logic to check which direction is pressed, and we adjust the snake's location accordingly.