Змея движется горизонтально

Я пытаюсь создать простую змеиную игру.

(function() {
  var canvas = document.getElementById('canvas'),
      ctx = canvas.getContext('2d'),
      x = 0,
      y = 0,
      speed = 2; 
      x_move = speed,
      y_move = 0,                          
      food_position_x = Math.floor(Math.random() * canvas.width / 10) * 10,
      food_position_y = Math.floor(Math.random() * canvas.height / 10) * 10,
      size_x = 10;    

  function eat() {   
   console.log('food_x:' + food_position_x + ' x:' + x + ' / food_y:' + food_position_y + ' y:' + y);
    if (Math.floor(y / 10) * 10 == food_position_y && Math.floor(x / 10) *10  == food_position_x) {  
    	size_x += 2;
      //throw new Error("MATCH!"); // This is not an error. Just trying to stop the script
    }
  }
  
  // Drawing
  function draw() {
    eat();
    requestAnimationFrame(function() {      
      draw();      
    });    
    // Draw the snake
    ctx.beginPath();
    ctx.rect(Math.floor(x/10)*10, Math.floor(y/10)*10, size_x, 10);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = '#ffffff'; 
    ctx.fill();
    ctx.closePath();

    // Draw the food
    ctx.beginPath(); 
    ctx.rect(Math.floor(food_position_x/10)*10, Math.floor(food_position_y/10)*10, 10, 10);
    ctx.fillStyle = "blue";
    ctx.fill();
    ctx.closePath();

    // Increase the value of x and y in order to animate
    x = x + x_move;
    y = y + y_move;       
  } 
  draw();

  // Key Pressing
  document.addEventListener('keydown', function(event) {
    switch(event.keyCode) {
      case 40: // Moving down
        if (x_move != 0 && y_move != -1) {
          x_move = 0;
          y_move = speed;
        }
      break;
      case 39: // Moving right
        if (x_move != -1 && y_move != 0) {
          x_move = speed;
          y_move = 0; 
        }
      break;
      case 38: // Moving top
        if (x_move != 0 && y_move != 1) {
          x_move = 0;
          y_move = -speed; 
        }
      break;
      case 37: // Moving left
        if (x_move != 1 && y_move != 0) {
          x_move = -speed;
          y_move = 0; 
        }
      break;
    }
  });
})();
canvas { background-color: #000022 }
<canvas id="canvas" width="400" height="400"></canvas>

Ответ 1

Вам нужно поддерживать array точек, которые в настоящее время занимают тело змеи, и добавлять новую точку (не unshift) в массив по мере приближения змеи и удаления точки из задней части массива (pop). Следующий код - стартер, вам нужно сделать это самостоятельно :).

(function () {
    const COLORS={ SNAKE:'#ff7bf5', FOOD:'blue' };
    var canvas = document.getElementById('canvas'),
        ctx = canvas.getContext('2d');
    var snake=[], score=0;
    var x, y, food_position_x, food_position_y, x_move, y_move;
    var frameCount=0, framesRequiredToMove=10;
    //the less the framesToMove the faster the sname moves
    function draw(){
        if(++frameCount==framesRequiredToMove){
            frameCount=0;
            move();
        }
        requestAnimationFrame(draw);
    }
    function init(){
        snake = [{x:3,y:0},{x:2,y:0},{x:1,y:0},{x:0,y:0}];
        snake.forEach((p)=>{plot(p.x,p.y,COLORS.SNAKE)})
        x=snake[0].x;y=snake[0].y;
        score=0;x_move=1;y_move=0;
        scoreboard.innerText=score;
        newfood();
        setTimeout(draw,1000);
    }
    function plot(x,y,color){
        ctx.beginPath();
        ctx.rect(x * 10, y * 10, 10, 10);
        ctx.fillStyle = color;
        ctx.fill();
        ctx.closePath();
    }
    function move(){
        snakepx.innerText = x;
        snakepy.innerText = y;
        x = x + x_move;
        y = y + y_move;
        // Advance The Snake
        plot(x,y,COLORS.SNAKE);
        snake.unshift({x:x,y:y});
        // Check food encounter
        if(x==food_position_x && y==food_position_y){
            scoreboard.innerText=++score;
            newfood();
        }
        else{
            var last=snake.pop();
            ctx.clearRect(last.x * 10, last.y * 10, 10, 10);
        }
    }
    function newfood(){
        food_position_x=Math.floor(Math.random() * canvas.width / 10);
        food_position_y=Math.floor(Math.random() * canvas.height / 10);
        plot(food_position_x,food_position_y,COLORS.FOOD);
        foodpx.innerText = food_position_x;
        foodpy.innerText = food_position_y;
    }
    init();

    // Key Pressing
    document.addEventListener('keydown', function (event) {
        event.preventDefault();
        switch (event.keyCode) {
            case 40: // Moving down
                if (x_move != 0 && y_move != -1) {
                    x_move = 0;
                    y_move = 1;
                }
                break;
            case 39: // Moving right
                if (x_move != -1 && y_move != 0) {
                    x_move = 1;
                    y_move = 0;
                }
                break;
            case 38: // Moving top
                if (x_move != 0 && y_move != 1) {
                    x_move = 0;
                    y_move = -1;
                }
                break;
            case 37: // Moving left
                if (x_move != 1 && y_move != 0) {
                    x_move = -1;
                    y_move = 0;
                }
                break;
        }
    });
})();
canvas {
    background-color: #000022;
    float: left;
}
<canvas id="canvas" width="400" height="180"></canvas>
<div style="margin-left: 410px">
    Snake: (<span id="snakepx"></span>, <span id="snakepy"></span>)<br>
    Food: (<span id="foodpx"></span>, <span id="foodpy"></span>)<br>
    Score: <span id="scoreboard"></span>
</div>

Ответ 2

Ну, когда у меня было свободное время, я создал свою собственную змею JS, чтобы продемонстрировать вам, как это можно сделать. Наиболее важные части находятся в этом. SnakeBody, где хранится массив тела, и this.moveForward(), где вы можете видеть, как тело обновляется.

https://jsfiddle.net/nooorz24/p8xtdv3h/13/

moveForward: function() {
    var next = this.getNextfieldValue();

    if (next == "frame" || next == "body") {
        console.log("You lose!")
        this.isAlive = false;
    } else {
        var newHead = this.getNextfieldCoords();
        this.draw.snake(newHead.x, newHead.y);
        this.body.unshift(newHead);
        if (next == "food") {
            this.generateFood();
            this.snakeSize++;
        } else {
            var last = this.body.pop();
            this.draw.empty(last.x, last.y);
        }
    }
},

Я попытался сделать это настолько читаемым, насколько мог, но заметьте, что это незавершенный пример и потребует дополнительных обновлений, чтобы играть в игру

Ответ 3

Я думаю, что вы ответили на массив массивом. Раньше я обнаружил, что Снейк лучше всего работает с массивом, отслеживая каждый блок змеи и проверяя, что любые два блока находятся в одном положении. Однако для движения вы должны напрямую управлять головой и следить за тем, чтобы тело было основано на позиции пространства массива, которое было впереди. Голова змеи будет первым элементом в массиве. Я не уверен, что вы имеете в виду, что не понимаете реализацию массива, но координаты для каждого блока будут элементом в массиве.

Ответ 4

Имейте переменную длины и укажите, что размер x или y зависит от направления, например:

(function() {
  var canvas = document.getElementById('canvas'),
      ctx = canvas.getContext('2d'),
      x = 0,
      y = 0,
      speed = 2,
      x_move = speed,
      y_move = 0,                          
      food_position_x = Math.floor(Math.random() * canvas.width / 10) * 10,
      food_position_y = Math.floor(Math.random() * canvas.height / 10) * 10,
      size_x = 10,
			size_y = 10,
			snake_length = 10;    

  function eat() {   
   console.log('food_x:' + food_position_x + ' x:' + x + ' / food_y:' + food_position_y + ' y:' + y);
    if (Math.floor(y / 10) * 10 == food_position_y && Math.floor(x / 10) *10  == food_position_x) {  
    	snake_length += 2;
      //throw new Error("MATCH!"); // This is not an error. Just trying to stop the script
    }
  }
  
  // Drawing
  function draw() {
    eat();
    requestAnimationFrame(function() {      
      draw();      
    });    
    // Draw the snake
    ctx.beginPath();
    ctx.rect(Math.floor(x/10)*10, Math.floor(y/10)*10, size_x, size_y);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = '#ffffff'; 
    ctx.fill();
    ctx.closePath();

    // Draw the food
    ctx.beginPath(); 
    ctx.rect(Math.floor(food_position_x/10)*10, Math.floor(food_position_y/10)*10, 10, 10);
    ctx.fillStyle = "blue";
    ctx.fill();
    ctx.closePath();

    // Increase the value of x and y in order to animate
    x = x + x_move;
    y = y + y_move;       
  } 
  draw();

  // Key Pressing
  document.addEventListener('keydown', function(event) {
    switch(event.keyCode) {
      case 40: // Moving down
        if (x_move != 0 && y_move != -1) {
          x_move = 0;
          y_move = speed;
					size_x = 10;
					size_y = snake_length;
        }
      break;
      case 39: // Moving right
        if (x_move != -1 && y_move != 0) {
          x_move = speed;
          y_move = 0; 
					size_x = snake_length;
					size_y = 10;
        }
      break;
      case 38: // Moving top
        if (x_move != 0 && y_move != 1) {
          x_move = 0;
          y_move = -speed; 
					size_x = 10;
					size_y = snake_length;
        }
      break;
      case 37: // Moving left
        if (x_move != 1 && y_move != 0) {
          x_move = -speed;
          y_move = 0; 
					size_x = snake_length;
					size_y = 10;
        }
      break;
    }
  });
})();
canvas { background-color: #000022 }
<canvas id="canvas" width="400" height="400"></canvas>

Ответ 5

Я делаю игру с помощью C++ soi может советовать сделать новый объект для каждой змеиной плитки и на ходу установить ее в родительскую позицию

function Tile(x, y)
{
  this.x = x;
  this.y = y;
}

Ответ 6

Чтобы отладить проблему "вниз" или "вверх", я бы добавил несколько консольных вызовов ("сообщение") в вашем коде для отладки.

В частности, добавьте некоторые сообщения консоли в оператор switch, чтобы вы знали, что правильное событие и ветвь запускаются. Например:

switch(event.keyCode) {
  case 40: 
    console.log('down');
    ...
  case 39: 
    console.log('right');
    ...
}

Затем добавьте все больше сообщений отладочного журнала, пока не найдете свою проблему.

Вы можете просматривать консольные сообщения в инструментах разработчика F12 в своем браузере по своему усмотрению во время игры.

Также убедитесь, что вы не вызываете ctx.translate(...) в контексте холста, чтобы перевернуть холст, это изменит направление оси x и/или y.