В попытке начать изучение Javascript я решил реализовать известную игру «Змея». Я старался как можно меньше следовать учебникам, чтобы лучше понять, что я делаю.
До сих пор я заставлял свою змею двигаться, есть пищу и «расти», однако при выращивании клетки не следуют за основной клеткой змеи. Я уже некоторое время пытался устранить неисправности, и некоторые возможные решения, которые я придумала, включают: начиная с нескольких ячеек, а не 1, сохраняя положение предыдущего расположения основной ячейки и помещая туда новую ячейку, или даже изменяя реализация полностью.
Я не уверен, какой путь выбрать, и мне кажется, что я близок к тому, чтобы заставить его работать, но просто не совсем. В настоящее время ячейки создаются, но перемещаются в родительскую ячейку и следуют за той же ячейкой.
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
const HEIGHT = 400;
const WIDTH = 400;
const SCALE = 20;
window.addEventListener("keydown", (event) => {
const direction = event.key.replace("Arrow", "");
snake.update(direction);
});
function setup() {
canvas.height = HEIGHT;
canvas.width = WIDTH;
food.createFood();
window.setInterval(() => {
context.clearRect(0, 0, WIDTH, HEIGHT);
snake.move(snake.xSpeed, snake.ySpeed);
food.drawFood();
snake.draw();
snake.shiftCells();
}, 200);
}
let snake = {
cells: [{ x: 200, y: 200 }],
position: {
x: 200,
y: 200,
},
xSpeed: SCALE,
ySpeed: 0,
length: 1,
draw: () => {
for (cell of snake.cells) {
context.fillStyle = "#C2F970";
context.fillRect(cell.x, cell.y, SCALE, SCALE);
}
},
update: (direction) => {
switch (direction) {
case "Up":
snake.ySpeed = -1 * SCALE;
snake.xSpeed = 0;
break;
case "Down":
snake.ySpeed = 1 * SCALE;
snake.xSpeed = 0;
break;
case "Left":
snake.xSpeed = -1 * SCALE;
snake.ySpeed = 0;
break;
case "Right":
snake.xSpeed = 1 * SCALE;
snake.ySpeed = 0;
break;
}
},
move: (xDist, yDist) => {
if (snake.cells[0].x == food.position.x && snake.cells[0].y == food.position.y) {
snake.eat();
}
// x-position
if (snake.cells[0].x + xDist < 0) {
snake.cells[0].x = WIDTH;
} else if (snake.cells[0].x + xDist > WIDTH) {
snake.cells[0].x = 0;
} else {
snake.cells[0].x += xDist;
}
// y-position
if (snake.cells[0].y + yDist < 0) {
snake.cells[0].y = HEIGHT;
} else if (snake.cells[0].y + yDist > HEIGHT) {
snake.cells[0].y = 0;
} else {
snake.cells[0].y += yDist;
}
},
shiftCells: () => {
for (let i = length; i > 1; i--) {
snake.cells[i] = snake.cells[i - 1];
}
},
eat: () => {
snake.grow();
food.createFood();
},
grow: () => {
snake.cells.push({
x: snake.cells[snake.length - 1].x,
y: snake.cells[snake.length - 1].y,
});
snake.cells[0].x += snake.xSpeed;
snake.cells[0].y += snake.ySpeed;
length++;
},
};
let food = {
position: {
x: 0,
y: 0,
},
createFood: () => {
food.position.x = SCALE * Math.floor(Math.random() * (WIDTH / SCALE));
food.position.y = SCALE * Math.floor(Math.random() * (HEIGHT / SCALE));
},
drawFood: () => {
context.fillStyle = "#D3FCD5";
context.fillRect(food.position.x, food.position.y, SCALE, SCALE);
},
};
setup();
Буду очень признателен за любые отзывы о том, как заставить ячейки следовать должным образом, и даже любые советы о том, как более правильно структурировать мой код (например, следует ли реализовать Snake в другом файле? класс?).