JS实现的贪吃蛇游戏案例详解
游戏规则
贪吃蛇游戏是一种非常经典的游戏,规则如下:
- 贪吃蛇每次只能往上、下、左、右四个方向的其中一个方向走;
- 贪吃蛇的身体每增加一节长度,分数就会增加一分;
- 贪吃蛇在吃到“食物”时身体长度加一,可以得到分数;
- 贪吃蛇撞到边界或者自己的身体就会死亡,游戏结束;
- 游戏过程中,可以随时暂停或重新开始。
实现过程
创建游戏区域
首先,我们需要在HTML中创建一个canvas元素,用于绘制游戏界面:
<canvas id="game" width="400" height="400"></canvas>
然后,在JS中获取这个canvas元素:
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
绘制贪吃蛇
我们可以通过一个数组来表示贪吃蛇:
let snake = [
{x: 3, y: 0},
{x: 2, y: 0},
{x: 1, y: 0},
{x: 0, y: 0},
];
数组中的每个元素都表示贪吃蛇的一个“身体”位置,x表示横坐标,y表示纵坐标。数组的第一个元素表示贪吃蛇的脑袋,最后一个元素表示贪吃蛇的尾巴。
我们需要绘制出这个贪吃蛇。可以使用canvas来绘制:
const SNAKE_SIZE = 10;
const SNAKE_COLOR = '#333';
function drawSnake() {
ctx.fillStyle = SNAKE_COLOR;
for (let i = 0, len = snake.length; i < len; i++) {
ctx.fillRect(snake[i].x * SNAKE_SIZE, snake[i].y * SNAKE_SIZE, SNAKE_SIZE, SNAKE_SIZE);
}
}
移动贪吃蛇
接下来,我们需要让贪吃蛇能够移动起来。贪吃蛇的移动是根据当前贪吃蛇头的位置和方向来计算的。我们需要记录贪吃蛇方向,以便下一次移动的时候根据方向进行计算。
let direction = 'right';
document.addEventListener('keydown', function(event) {
if (event.keyCode === 37 && direction !== 'right') {
direction = 'left';
} else if (event.keyCode === 38 && direction !== 'down') {
direction = 'up';
} else if (event.keyCode === 39 && direction !== 'left') {
direction = 'right';
} else if (event.keyCode === 40 && direction !== 'up') {
direction = 'down';
}
});
在键盘按下事件的回调函数中,我们根据按键的keyCode来判断用户输入的方向,并修改方向变量。
然后,我们需要在每个游戏循环中根据方向来计算蛇头的位置,并将位置添加到数组的头部。同时,我们需要将数组的尾部去掉,这样就实现了贪吃蛇的移动。
let intervalId;
function startGame() {
intervalId = setInterval(() => {
let {x, y} = snake[0];
switch (direction) {
case 'up':
y--;
break;
case 'right':
x++;
break;
case 'down':
y++;
break;
case 'left':
x--;
break;
}
snake.unshift({x, y});
snake.pop();
}, 100);
}
注意,由于 setInterval 函数返回一个唯一的 ID,我们需要保存这个 ID,以便在需要停止游戏时能够清除时间循环:
function stopGame() {
clearInterval(intervalId);
}
添加食物
贪吃蛇游戏中,蛇可以吃食物,这时蛇的身体长度会增加。我们需要在游戏区域内添加食物,并在贪吃蛇吃到食物时增加贪吃蛇的身体长度。
let food = {
x: Math.floor(Math.random() * (canvas.width / SNAKE_SIZE)),
y: Math.floor(Math.random() * (canvas.height / SNAKE_SIZE)),
};
const FOOD_COLOR = '#f00';
function drawFood() {
ctx.fillStyle = FOOD_COLOR;
ctx.fillRect(food.x * SNAKE_SIZE, food.y * SNAKE_SIZE, SNAKE_SIZE, SNAKE_SIZE);
}
我们可以在游戏开始时生成一个随机位置的食物,并在绘制游戏区域时绘制食物。当贪吃蛇的蛇头和食物位置相同时,就表示贪吃蛇已经吃到了食物,这时我们就需要在贪吃蛇的头部添加一个位置,表示身体长度增加了。
function eatFood() {
const {x: headX, y: headY} = snake[0];
if (headX === food.x && headY === food.y) {
console.log('Eat food!');
food = {
x: Math.floor(Math.random() * (canvas.width / SNAKE_SIZE)),
y: Math.floor(Math.random() * (canvas.height / SNAKE_SIZE)),
};
snake.unshift({x: headX, y: headY});
}
}
游戏结束
当贪吃蛇撞到边界或者自己的身体,游戏就结束了。我们需要在游戏循环中判断游戏是否结束,并在结束时停止游戏循环。
function isGameOver() {
const {x: headX, y: headY} = snake[0];
for (let i = 1, len = snake.length; i < len; i++) {
if (snake[i].x === headX && snake[i].y === headY) {
return true;
}
}
if (headX < 0 || headX >= canvas.width / SNAKE_SIZE || headY < 0 || headY >= canvas.height / SNAKE_SIZE) {
return true;
}
return false;
}
function checkGameOver() {
if (isGameOver()) {
console.log('Game over!');
stopGame();
}
}
示例说明
示例1
以下是一个简单的示例代码:https://codepen.io/happycoder01/pen/rNwdYjV
该示例实现了一个基本的贪吃蛇游戏,但没有进行模块化和优化,代码难以理解和维护。
示例2
以下是一个较为完整的示例代码:https://codepen.io/happycoder01/pen/QWvqyMa
该示例对代码进行了模块化和优化,将游戏逻辑和绘制逻辑分开,减少了代码的耦合性,同时使用了ES6的语法和面向对象编程的思想,代码更加简洁和易于维护。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JS实现的贪吃蛇游戏案例详解 - Python技术站