[英]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。event.preventDefault()
進行按鍵操作,以便在用戶控制蛇時屏幕不會移動。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.