簡體   English   中英

嘗試獲取數組的最后一個對象並將其移動到前面以在香草 JS/畫布蛇游戲中移動蛇

[英]Trying to take the last object of an array and move it to the front for movement of snake in vanilla JS/canvas snake game

我一直在嘗試在沒有任何教程的情況下構建一個蛇游戲應用程序,並且已經在邏輯問題上停留了好幾天。 從下面的代碼筆中,您可以看到我的蛇在移動,但它不像繩索那樣移動,它只是作為一個“塊”或碎片粘在一起的單元四處移動。

我相信你們中的大多數人都可以閉上眼睛做這樣的事情,但我想知道你是否可以說服我離開窗台。 我想知道我是否已經把它放在一起,以至於我需要重新思考我是如何建立它的,也許(大部分)重新開始?

在第 43 - 47 行,您可以看到我嘗試將最后一個數組項 '''pop()''' '''unshift()''' 移回最前面,然后重新繪制新數組到畫布。 我可以在我的 '''updateSnake()''' 函數中使用 JS 和 Canvas 來做到這一點,如果不能,你能把我推到我的邏輯有缺陷的地方嗎?

謝謝!

https://codepen.io/constequalsexcel/pen/eYNjRER

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Snake Game</title>
    <link rel="stylesheet" href="styles.css" />
  </head>
  <header id="header">Snake Game</header>
  <div id="score-box">
    <h1>SCORE</h1>
    <h3 id="score">0</h3>
  </div>
  <body>
    <canvas id="gameCanvas" width="500" height="500"></canvas>
    <script src="scripts.js"></script>
  </body>
</html>

CSS

#gameCanvas {
  margin: auto;
  display: block;
}

#header {
  text-align: center;
  margin: 30px 0 100px 0;
  font-size: 35px;
}

#score {
  margin-left: 60px;
}

JS

let canvas = document.getElementById("gameCanvas");
let ctx = canvas.getContext("2d");
let snakeDirection;
document.addEventListener("keydown", moveSnakeKeys, false);
let appleX;
let appleY;
let score = 0;

createApple();

class Snake {
  constructor() {
    this.body = [{ x: 50, y: 200 }, { x: 34, y: 200 }, { x: 18, y: 200 }];
    this.snakeSpeedX = 15;
    this.snakeSpeedY = 15;
    this.color = "green";
    this.snakeSize = 15;
  }

  drawSnake() {
    ctx.fillStyle = this.color;
    for (let i = 0; i < this.body.length; i++) {
      ctx.fillRect(
        this.body[i].x,
        this.body[i].y,
        this.snakeSize,
        this.snakeSize
      );
    }
    ctx.fill();
  }

  // remove 'tail' from snake
  // store 'tail' in a variable
  // check direction of snake
  // place 'tail' infront of snake body

  updateSnake() {
    if (snakeDirection === "right") {
      for (let i = 0; i < this.body.length; i++) {
        this.body[i].x += this.snakeSpeedX;
        // let tail = this.body.pop()
        // console.log(tail)
        // tail.x = this.body[0].x
        // tail.y = this.body[0].y
        // this.body.unshift(tail)
      }
    } else if (snakeDirection === "down") {
      for (let i = 0; i < this.body.length; i++) {
        this.body[i].y += this.snakeSpeedY;
      }
    } else if (snakeDirection === "left") {
      for (let i = 0; i < this.body.length; i++) {
        this.body[i].x -= this.snakeSpeedX;
      }
    } else if (snakeDirection === "up") {
      for (let i = 0; i < this.body.length; i++) {
        this.body[i].y -= this.snakeSpeedY;
      }
    }
    this.drawSnake();
  }
}

const snake = new Snake();

function animate() {
  ctx.fillStyle = "black";
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  snake.updateSnake();
  ctx.fillStyle = "red";
  ctx.fillRect(appleX, appleY, 15, 15);
  ctx.fill();
  updateScore();
  gameOver();
}

setInterval(animate, 200);

function moveSnakeKeys(e) {
  if (e.code === "ArrowRight" && snakeDirection != "left") {
    snakeDirection = "right";
  } else if (e.code === "ArrowLeft" && snakeDirection != "right") {
    snakeDirection = "left";
  } else if (e.code === "ArrowUp" && snakeDirection != "down") {
    snakeDirection = "up";
  } else if (e.code === "ArrowDown" && snakeDirection != "up") {
    snakeDirection = "down";
  }
}

function createApple() {
  appleX = Math.floor(Math.random() * (canvas.width - 15));
  appleY = Math.floor(Math.random() * (canvas.height - 15));
}

function updateScore() {
  if (
    snake.body[0].x < appleX + 15 &&
    snake.body[0].x + 15 > appleX &&
    snake.body[0].y < appleY + 15 &&
    snake.body[0].y + 15 > appleY
  ) {
    ctx.clearRect(appleX, appleY, 15, 15);
    createApple();
    score = score + 1;
    document.getElementById("score").innerText = score;
    growSnake();
  }
}

function growSnake() {
  let xLength = snake.body[snake.body.length - 1].x - 16;
  let yLength = snake.body[snake.body.length - 1].y;
  snake.body.push({ x: xLength, y: yLength });
}

function gameOver() {
  if (
    snake.body[0].x > canvas.width - snake.snakeSpeedX ||
    snake.body[0].x < 0
  ) {
    alert("Game Over!");
  } else if (
    snake.body[0].y > canvas.height - snake.snakeSpeedY ||
    snake.body[0].y < 0
  ) {
    alert("Game Over!");
  }
}

你的直覺很好。 缺失的部分實際上是更新新頭部以朝着您想要的方向移動。

updateSnake() {
  const dir = {
    up: {x: 0, y: -this.snakeSize},
    down: {x: 0, y: this.snakeSize},
    left: {x: -this.snakeSize, y: 0},
    right: {x: this.snakeSize, y: 0},
  }[snakeDirection] || {x: 0, y: 0};
  this.body.unshift(this.body.pop());
  this.body[0].x = this.body[1].x + dir.x;
  this.body[0].y = this.body[1].y + dir.y;
  this.drawSnake();
}

條件有點難看,所以對象是消除它的簡單方法。 如果您(理所當然地)擔心在每一幀中分配它,請將其范圍限定在類中。

由於snakeDirection方向在腳本開始時未初始化,我使用|| {x: 0, y: 0} || {x: 0, y: 0}如果在對象中找不到snakeDirection鍵,則將dir設置為默認值。

其他一些提示:

  • snakeDirection是一個全局是不必要的,打破了封裝。 將其作為參數傳遞給updateSnake
  • this.drawSnake()移出updateSnake函數——更好地將關注點分開並將這些函數調用移至父函數。
  • 同樣, animate不應調用gameOver函數。 這個函數實際上不會導致游戲結束,所以它的命名有點誤導。 它檢查邊界,這應該是游戲或蛇類的責任。 它還會在游戲結束時發送垃圾郵件對話框,但我確定這是一個 WIP。
  • 考慮使用一致的網格大小,例如 15 或 20 像素。
  • 使用event.preventDefault()進行按鍵操作,以便在用戶控制蛇時屏幕不會移動。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM