这个中秋可是悲催,别人放假,我还得在家办公写项目,带娃的时间都没有,这不,娃要缠着陪她玩积木游戏,哎,心中有事,陪娃都陪不好,咋整,灵机一动,先搞个小游戏让娃耍个把小时,毕竟孩子长时间对着电脑不好,写个贪吃蛇吧,能玩很久。
先看一下简单的界面是这样的:
网页游戏,比较简单,一个页面就搞定了,代码是这样的,直接生成一个 html 就能玩了。
创建一个简单的贪吃蛇网页游戏,使用 HTML、CSS 和 JavaScript 三件套,简单高效。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Snake Game</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #333;
margin: 0;
}
canvas {
border: 1px solid #fff;
background-color: #000;
}
</style>
</head>
<body>
<canvas id="gameCanvas" width="400" height="400"></canvas>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const gridSize = 20;
const tileCount = canvas.width / gridSize;
let snake = [{ x: 10, y: 10 }];
let food = { x: 5, y: 5 };
let direction = { x: 0, y: 0 };
let nextDirection = { x: 0, y: 0 };
let speed = 200;
function gameLoop() {
// Update snake direction
direction = nextDirection;
// Move snake
const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };
snake.unshift(head);
// Check for food collision
if (head.x === food.x && head.y === food.y) {
placeFood();
} else {
snake.pop();
}
// Check for wall collision
if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount) {
gameOver();
return;
}
// Check for self collision
for (let i = 1; i < snake.length; i++) {
if (snake[i].x === head.x && snake[i].y === head.y) {
gameOver();
return;
}
}
drawGame();
}
function drawGame() {
// Clear canvas
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw snake
ctx.fillStyle = 'lime';
snake.forEach(part => {
ctx.fillRect(part.x * gridSize, part.y * gridSize, gridSize, gridSize);
});
// Draw food
ctx.fillStyle = 'red';
ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize, gridSize);
}
function placeFood() {
food.x = Math.floor(Math.random() * tileCount);
food.y = Math.floor(Math.random() * tileCount);
// Make sure food doesn't appear on the snake
for (let i = 0; i < snake.length; i++) {
if (snake[i].x === food.x && snake[i].y === food.y) {
placeFood();
}
}
}
function changeDirection(event) {
switch (event.keyCode) {
case 37: // Left arrow
if (direction.x === 0) {
nextDirection = { x: -1, y: 0 };
}
break;
case 38: // Up arrow
if (direction.y === 0) {
nextDirection = { x: 0, y: -1 };
}
break;
case 39: // Right arrow
if (direction.x === 0) {
nextDirection = { x: 1, y: 0 };
}
break;
case 40: // Down arrow
if (direction.y === 0) {
nextDirection = { x: 0, y: 1 };
}
break;
}
}
function gameOver() {
alert('Game Over!');
snake = [{ x: 10, y: 10 }];
direction = { x: 0, y: 0 };
nextDirection = { x: 0, y: 0 };
placeFood();
}
document.addEventListener('keydown', changeDirection);
setInterval(gameLoop, speed);
placeFood();
</script>
</body>
</html>
前端三件套:
HTML:包含一个 <canvas>
元素,贪吃蛇游戏将会在这个画布上渲染。
CSS:简单地设置了画布的外观。
JavaScript:游戏逻辑,包括:
gameLoop
函数:负责蛇的移动、碰撞检测、食物生成等。drawGame
函数:绘制蛇和食物。placeFood
函数:随机放置食物在画布上。changeDirection
函数:监听键盘事件,改变蛇的移动方向。gameOver
函数:处理游戏结束的逻辑。
下面再详细解释一下这个小游戏的实现逻辑:
这个贪吃蛇游戏使用 HTML、CSS 和 JavaScript 编写,代码实现的逻辑和流程如下:
1. HTML 部分
<canvas id="gameCanvas" width="400" height="400"></canvas>
- 使用
<canvas>
元素作为游戏画布,游戏会在这个区域绘制蛇、食物等内容。 - 设置
id="gameCanvas"
以便在 JavaScript 中通过document.getElementById
获取它。 width
和height
属性定义了画布的尺寸为 400x400 像素。
2. CSS 部分
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #333;
margin: 0;
}
canvas {
border: 1px solid #fff;
background-color: #000;
}
- 使用 CSS 将画布居中,背景设为黑色。
- 设置画布的边框和背景颜色,增强视觉效果。
3. JavaScript 部分
JavaScript 部分包含了游戏的核心逻辑,包括蛇的移动、食物的生成、碰撞检测、绘制和用户输入的处理。
3.1. 初始化变量
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const gridSize = 20;
const tileCount = canvas.width / gridSize;
let snake = [{ x: 10, y: 10 }];
let food = { x: 5, y: 5 };
let direction = { x: 0, y: 0 };
let nextDirection = { x: 0, y: 0 };
let speed = 200;
canvas
:获取画布元素。ctx
:获取画布的 2D 渲染上下文,用于绘制图形。gridSize
:网格大小,每个网格 20x20 像素。tileCount
:计算画布中网格的数量,canvas.width / gridSize
(这里为 20x20 个网格)。snake
:蛇的初始位置,初始为一个对象数组,蛇头位置在{x: 10, y: 10}
。food
:食物的初始位置{x: 5, y: 5}
。direction
和nextDirection
:蛇的当前移动方向和下一个移动方向。speed
:控制游戏循环的速度,单位是毫秒。
3.2. 游戏主循环
function gameLoop() {
// Update snake direction
direction = nextDirection;
// Move snake
const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };
snake.unshift(head);
// Check for food collision
if (head.x === food.x && head.y === food.y) {
placeFood();
} else {
snake.pop();
}
// Check for wall collision
if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount) {
gameOver();
return;
}
// Check for self collision
for (let i = 1; i < snake.length; i++) {
if (snake[i].x === head.x && snake[i].y === head.y) {
gameOver();
return;
}
}
drawGame();
}
gameLoop
是游戏的主循环函数,使用setInterval
在一定时间间隔内重复调用,实现游戏的实时更新。- 移动方向更新:更新蛇的移动方向。
- 移动蛇:创建蛇头的新位置,根据方向调整
x
和y
坐标,将新头部添加到snake
数组的开头。 - 检查食物碰撞:如果蛇头和食物位置相同,调用
placeFood
生成新的食物位置;否则,移除蛇尾(snake.pop()
),维持蛇的长度。 检测碰撞:
- 墙壁碰撞:如果蛇头的位置超出画布范围,调用
gameOver
函数结束游戏。 - 自身碰撞:如果蛇头与身体的任何部分重叠,调用
gameOver
函数结束游戏。
- 墙壁碰撞:如果蛇头的位置超出画布范围,调用
- 绘制游戏:调用
drawGame
函数更新画布。
3.3. 绘制游戏
function drawGame() {
// Clear canvas
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw snake
ctx.fillStyle = 'lime';
snake.forEach(part => {
ctx.fillRect(part.x * gridSize, part.y * gridSize, gridSize, gridSize);
});
// Draw food
ctx.fillStyle = 'red';
ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize, gridSize);
}
drawGame
函数负责绘制游戏的每一帧。- 清空画布:用黑色填充整个画布,清除之前的绘制内容。
- 绘制蛇:遍历
snake
数组,在蛇每个部分的位置上绘制一个绿色矩形。 - 绘制食物:在
food
的位置绘制一个红色矩形。
3.4. 生成新食物
function placeFood() {
food.x = Math.floor(Math.random() * tileCount);
food.y = Math.floor(Math.random() * tileCount);
// Make sure food doesn't appear on the snake
for (let i = 0; i < snake.length; i++) {
if (snake[i].x === food.x && snake[i].y === food.y) {
placeFood();
}
}
}
placeFood
随机在画布上放置食物。- 防止食物出现在蛇身上:如果生成的食物位置在蛇身上,则递归调用
placeFood
重新生成位置。
3.5. 处理方向改变
function changeDirection(event) {
switch (event.keyCode) {
case 37: // Left arrow
if (direction.x === 0) {
nextDirection = { x: -1, y: 0 };
}
break;
case 38: // Up arrow
if (direction.y === 0) {
nextDirection = { x: 0, y: -1 };
}
break;
case 39: // Right arrow
if (direction.x === 0) {
nextDirection = { x: 1, y: 0 };
}
break;
case 40: // Down arrow
if (direction.y === 0) {
nextDirection = { x: 0, y: 1 };
}
break;
}
}
changeDirection
函数监听键盘事件,更新蛇的移动方向。- 确保蛇不能直接反方向移动:例如,蛇正在向右移动时,不能直接按左键,否则会导致游戏结束。
3.6. 游戏结束
function gameOver() {
alert('Game Over!');
snake = [{ x: 10, y: 10 }];
direction = { x: 0, y: 0 };
nextDirection = { x: 0, y: 0 };
placeFood();
}
gameOver
函数在蛇撞墙或自身时调用,显示“游戏结束”信息,并重置游戏状态。
3.7. 启动游戏
document.addEventListener('keydown', changeDirection);
setInterval(gameLoop, speed);
placeFood();
- 事件监听:监听键盘事件,调用
changeDirection
函数。 - 启动游戏循环:使用
setInterval
定期调用gameLoop
,使游戏持续运行。 - 初始食物生成:调用
placeFood
函数生成初始食物位置。
最后小结一下
- 这个贪吃蛇游戏使用了 JavaScript 进行画布绘制、碰撞检测和用户输入处理。
- 游戏循环 (
gameLoop
) 不断更新蛇的位置、检查碰撞、绘制游戏元素,形成动画效果。 - 使用键盘事件来改变蛇的方向,实现玩家的控制。
好了,现在可以静静的写项目了,专心致志,效率翻倍。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。