前言
【贪吃蛇小游戏】主要运用HTML5中的Canvas(画布)实现游戏界面,运用JavaScript编写小游戏的主要逻辑。HTML5中的<canvas>
元素被用来通过 JavaScript(Canvas API 或 WebGL API)绘制图形及游戏界面。
项目分析
1.、项目结构
2、 源代码
1.HTML部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>贪吃蛇小游戏</title>
<link rel="stylesheet" href="snake.css">
</head>
<body>
<canvas id="gameCanvas" width="800" height="800"></canvas>
<button id="restartButton" style="display: none;" onclick="restartGame()">重新开始</button>
<script src="snake.js"></script>
</body>
</html>
其中,<canvas>
元素在 HTML 中被用来通过 JavaScript 绘制游戏画面,在这个画布上绘制了一个 800x800 像素的游戏界面。
2.CSS部分
在snake.css
中设置 Canvas 和按钮(button)的样式。
body {
display: flex;/*设置元素的显示类型为弹性盒子(Flexbox)*/
flex-direction: column;/*设置主轴的方向(行或列),使子元素沿着垂直方向(主轴变为垂直方向)排列。*/
justify-content: center;/*设置弹性项目在主轴上的对齐方式*/
align-items: center;/*设置弹性项目在交叉轴上的对齐方式*/
height: 100vh;/*用于设置元素的高度。vh(长度单位),代表“视口高度”(Viewport Height)的1%。将元素的高度设置为视口(通常是浏览器窗口的可见部分)高度的100%,即让元素的高度充满整个视口的高度。*/
margin: 0;
background-color: #acd8ec;
}
canvas {
border: 1px solid #9db326;/*为一个元素设置宽度为1像素、样式为实线、颜色为黑色的边框。*/
background-color: #e7eccf;
}
button {
display: none;/*该元素会从文档布局中完全消失,就像它从未存在过一样。它不会占据任何空间,也不会在页面上生成任何盒子(box model),并且其内部的子元素也会被一并隐藏,不会被渲染或显示。*/
margin-top: 20px; /*上边距为20像素*/
padding: 10px 20px;/* 内边距:上下内边距为10像素,左右内边距为20像素 */
font-size: 20px;
font-weight: bold;/* 使按钮内的文本加粗 */
background-color: #ecee80;
border-radius: 5px; /* 边框圆角 */
cursor: pointer;/* 鼠标悬停时显示手指形状,表示可点击 */
position: absolute;/*用于设置一个元素的定位方式为绝对定位*/
/*
绝对定位有几个特点:
1、脱离文档流:元素不再占据其在文档流中的原始空间,其后的元素会填补其留下的空间。
2、相对于最近的已定位祖先元素定位:如果没有这样的祖先元素,则相对于初始包含块(通常是视口或HTML文档的根元素)。
3、不改变其他元素的布局:除了不占据原本的空间外,它也不会影响到其他元素的布局。
*/
}
3.JavaScript部分
游戏的主要逻辑分为8个部分:
-
- 初始化 Canvas 和游戏变量
-
- 初始化游戏
-
- 绘制单个格子
-
- 绘制蛇
-
- 绘制食物
-
- 更新蛇的位置和状态
-
- 游戏循环
-
- 重新开始游戏
/**
* 1. 初始化 Canvas 和游戏变量
*/
const canvas = document.getElementById("gameCanvas");//获取 Canvas 元素及其上下文
const ctx = canvas.getContext("2d");//获取 2D 绘图上下文,并将其存储在 ctx 变量中
const restartButton = document.getElementById("restartButton");//获取 restartButton 元素
const gridSize = 20; // 设置每个格子的大小
const rows = Math.floor(canvas.height / gridSize);//行数
const cols = Math.floor(canvas.width / gridSize);//列数
let snake = [];
let food = {};
let direction = { x: 1, y: 0 };
let lastDirection = { ...direction };
let gameOver = false;
/**
* 2.初始化游戏
*/
function initGame() {
// 初始化蛇的位置和长度
snake = [{ x: Math.floor(cols / 2), y: Math.floor(rows / 2) }, { x: Math.floor(cols / 2) + 1, y: Math.floor(rows / 2) }];
// 初始化食物的位置
food = {
x: Math.floor(Math.random() * cols),
y: Math.floor(Math.random() * rows),
};
// 初始化蛇的方向
direction = { x: 1, y: 0 }; // 向右
lastDirection = { x: 1, y: 0 }; // 上次的方向也设置为向右,这对于第一次移动可能不是必需的,但保持一致性
// 游戏状态
gameOver = false;
// 隐藏重启按钮
restartButton.style.display = "none";
// 开始游戏循环
gameLoop();
}
/**
* 3.绘制单个格子
*/
function drawCell(x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x * gridSize, y * gridSize, gridSize, gridSize);
ctx.strokeStyle = "#000";
ctx.lineWidth = 2; // 可以根据需要调整
ctx.strokeRect(x * gridSize, y * gridSize, gridSize, gridSize);
}
/**
* 4.绘制蛇
*/
function drawSnake() {
snake.forEach((part) => drawCell(part.x, part.y, "#409EFF"));
}
/**
* 5.绘制食物
*/
function drawFood() {
drawCell(food.x, food.y, "#E6A23C");
}
/**
* 6.更新蛇的位置和状态
*/
function updateSnake() {
const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };
// 注意:在吃掉食物后,应该先添加新头部,再移除尾部
if (head.x === food.x && head.y === food.y) {
food = {
x: Math.floor(Math.random() * cols),
y: Math.floor(Math.random() * rows),
};
} else {
snake.pop();
}
snake.unshift(head);
// 撞墙或撞到自己
if (
head.x < 0 ||
head.x >= cols ||
head.y < 0 ||
head.y >= rows ||
snake.slice(1).some((part) => part.x === head.x && part.y === head.y)
) {
gameOver = true;
}
// 更新上次的方向
lastDirection = direction;
}
/**
* 7.游戏循环
*/
function gameLoop() {
if (!gameOver) {
// 清除画布并绘制食物和蛇
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawFood();
updateSnake();
drawSnake();
setTimeout(gameLoop, 100);
} else {
//游戏结束,显示“Game Over”和重新开始按钮
ctx.font = "100px Arial";
ctx.fillStyle = "#F56C6C";
ctx.fillText("Game Over", canvas.width / 6, canvas.height / 2.5);
restartButton.style.display = "block"; // 显示重新开始按钮
}
}
// 监听键盘事件来改变蛇的方向
window.addEventListener("keydown", (event) => {
switch (event.key) {
case "ArrowUp":
if (lastDirection.y === 0) direction = { x: 0, y: -1 };
break;
case "ArrowDown":
if (lastDirection.y === 0) direction = { x: 0, y: 1 };
break;
case "ArrowLeft":
if (lastDirection.x === 0) direction = { x: -1, y: 0 };
break;
case "ArrowRight":
if (lastDirection.x === 0) direction = { x: 1, y: 0 };
break;
}
});
/**
* 8.重新开始游戏
*/
function restartGame() {
initGame(); // 重新开始游戏
}
// 绑定重启按钮的点击事件
restartButton.addEventListener("click", restartGame);
initGame(); // 启动游戏
总结
简易版的贪吃蛇小游戏可以实现上下左右控制贪吃蛇的移动方向,当然各位也可以在这个基础上做一些改进和优化,使得小游戏的玩法可以更加复杂多变,增加游戏趣味性。
PS:
参考文档
HTML5(Canvas):https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/canvas