一、游戏简介
贪吃蛇是一款经典的电子游戏,最早在1976年由Gremlin公司推出,名为"Blockade"。游戏的玩法简单却富有挑战性,玩家控制一条蛇在封闭的场地内移动,通过吃食物增长身体,同时避免撞到自己的身体或场地边界。随着时间的推移,贪吃蛇游戏经历了多次演变,但其核心玩法依然受到玩家的喜爱。
二、为什么选择贪吃蛇游戏
经典性:贪吃蛇是一款历史悠久的游戏,其经典性使得它成为学习编程和游戏开发的理想选择。
简单性:游戏规则简单,易于理解,适合初学者作为编程练习项目。
互动性:贪吃蛇游戏具有高度的互动性,玩家需要快速反应和策略思考。
可扩展性:基础游戏可以扩展多种功能,如增加难度级别、特殊道具等,为学习者提供更多实践机会。
三、游戏目标
贪吃蛇游戏的主要目标是控制蛇头吃到随机出现在游戏场地的苹果,每吃到一个苹果,蛇的身体就会增长一段。玩家需要避免蛇头撞到自己的身体或游戏场地的边界。游戏的难度会随着蛇身的增长而增加,玩家的目标是尽可能获得更高的分数。
四、游戏界面设计
游戏界面通常由以下几个部分组成:
游戏画布:一个矩形区域,作为蛇移动和吃苹果的场所。
蛇:由多个小方块组成,每个方块代表蛇的身体部分,蛇头通常有特殊的标识。
苹果:一个单独的方块,随机出现在游戏画布上,作为蛇的食物。
得分板:显示玩家当前的得分和游戏等级。
五、游戏逻辑概述
游戏逻辑主要包括以下几个方面:
初始化:设置游戏初始状态,包括蛇的位置、长度和方向,苹果的位置,以及得分和等级。
键盘控制:监听键盘按键,根据玩家的输入改变蛇的移动方向。
移动逻辑:更新蛇的位置,使其按照指定方向移动。
碰撞检测:检查蛇头是否撞到自己、边界或苹果。
吃苹果:如果蛇头碰到苹果,更新苹果的位置,增长蛇的身体,并增加得分。
游戏结束:如果蛇撞到自己或边界,显示游戏结束的提示,并结束游戏循环。
得分和等级:根据吃到的苹果数量增加得分,并根据得分调整游戏难度。
六、创建基本的HTML5文档结构
在创建贪吃蛇游戏之前,首先需要构建一个基本的HTML5文档结构。这个结构包括了文档的头部(head)和主体(body),其中头部用于引入CSS样式和JavaScript脚本,而主体则包含了游戏的所有元素。
源代码示例 - HTML5文档结构
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="styles/base.css">
<link rel="stylesheet" href="styles/snake.css">
</head>
<body>
<!-- 游戏画布和元素将在此处添加 -->
<script src="scripts/snake.js"></script>
</body>
</html>
设定游戏画布 (<div id="box">
)
游戏画布是一个<div>
元素,它作为游戏的容器,包含了蛇、苹果和得分板。这个<div>
具有固定的宽度和高度,并且使用CSS样式来设置其位置和外观。
源代码示例 - HTML中的游戏画布
<div id="box">
<!-- 蛇的身体由列表项组成,苹果是一个div,得分板将在JavaScript中动态添加 -->
<ul id="snake"></ul>
<div id="apple"></div>
</div>
<div id="score">得分: <span id="score-value">0</span> 等级: <span id="level-value">1</span></div>
添加游戏元素(蛇头、蛇身、苹果、得分板)
蛇头 :通常用一个带有图片的
<li>
元素表示,这个<li>
是<ul id="snake">
的第一个子元素。蛇身 :由多个
<li>
元素组成,这些元素将通过JavaScript动态添加到蛇的列表中。苹果 :用一个
<div id="apple">
表示,它的位置将通过JavaScript动态设置。得分板 :一个包含得分和等级的
<div>
元素,位于游戏画布之外。
源代码示例 - JavaScript中添加蛇头和蛇身
javascript
window.onload = function() {
var snakeList = document.getElementById('snake');
var snakeHead = document.createElement('li');
snakeHead.innerHTML = '<img src="head.png" alt="蛇头">'; // 假设有一个蛇头图片
snakeList.appendChild(snakeHead);
// 初始蛇身长度,例如5个单位
for (var i = 0; i < 5; i++) {
var snakeBodyPart = document.createElement('li');
snakeList.appendChild(snakeBodyPart);
}
var apple = document.getElementById('apple');
// 设置苹果的初始位置
apple.style.left = '100px';
apple.style.top = '100px';
};
七、效果图
八、完整代码
HTML
html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="base.css" />
<link rel="stylesheet" href="snake.css" />
<script src="snake.js"></script>
</head>
<body>
<div id="score">
得分: <span>0</span>
等级: <span>1</span>
</div>
<div id="box">
<ul id="snake">
<li class="heihei" id="head"><img src="right.png" alt="" /></li>
<li class="heihei"></li>
<li class="heihei"></li>
<li class="heihei"></li>
<li class="heihei"></li>
<li class="heihei"></li>
<li class="heihei"></li>
<li class="heihei"></li>
</ul>
<div id="apple"></div>
</div>
<script>
</script>
</body>
</html>
snake.css
css
#box{
width: 800px;
height: 600px;
position: relative;
background-color: #d5e3bd;
border: 1px solid #000;
margin: 30px auto;
}
#snake{
/*position: absolute;*/
/*top: 200px;*/
/*left: 350px;*/
}
.heihei{
width: 20px;
height: 20px;
/*border: 1px solid #000;*/
border-radius: 10px;
background-color: rgb(13, 113, 85);
position: absolute;
text-align: center;
line-height: 20px;
position: absolute;
top: 200px;
left: 350px;
color: white;
}
#head img{
width: 20px;
}
#apple{
width: 20px;
height: 20px;
background-color: darkred;
position: absolute;
top: 140px;
left: 400px;
}
#score{
width: 100px;
height: 100px;
border: 1px solid #000;
position: absolute;
text-align: center;
line-height: 100px;
left: 1100px;
z-index: 1;
}
base.css
css
@charset "UTF-8";
/*css 初始化 */
html, body, ul, li, ol, dl, dd, dt, p, h1, h2, h3, h4, h5, h6, form, fieldset, legend, img {
margin: 0;
padding: 0;
}
/*各浏览器显示不同,去掉蓝色边框*/
fieldset, img, input, button {
border: none;
padding: 0;
margin: 0;
outline-style: none;
}
ul, ol {
list-style: none;
}
/*统一组合框的默认样式*/
input {
padding-top: 0;
padding-bottom: 0;
font-family: "sums-song", "宋体";
}
select, input, button {
vertical-align: middle;
}
select, input, textarea {
font-size: 12px;
margin: 0;
}
/*防止拖动 影响布局*/
textarea {
resize: none;
}
/*去掉行内替换元素空白缝隙*/
img {
border: 0;
vertical-align: middle;
}
table {
border-collapse: collapse;
}
body {
font: 12px/150% Arial, Verdana, "\5b8b\4f53"; /*宋体 unicode */
color: #666;
background: #fff;
}
/*清除浮动*/
.clearfix:before, .clearfix:after {
content: "";
display: table;
}
.clearfix:after {
clear: both;
}
.clearfix {
*zoom: 1; /*IE/7/6*/
}
a {
color: #666;
text-decoration: none;
}
a:hover {
color: #C81623;
}
h1, h2, h3, h4, h5, h6 {
text-decoration: none;
font-weight: normal;
font-size: 100%;
}
s, i, em {
font-style: normal;
text-decoration: none;
}
/*京东色*/
.col-red {
color: #C81623 !important;
}
/*公共类*/
.w {
/*版心 提取 */
width: 1210px;
margin: 0 auto;
}
.fl {
float: left;
}
.fr {
float: right;
}
.al {
text-align: left;
}
.ac {
text-align: center;
}
.ar {
text-align: right;
}
.hide {
display: none;
}
js代码
javascript
window.onload = function() {
var ul = document.getElementById("snake");
var lis = ul.children;
var head = lis[0];
var img = head.getElementsByTagName("img")[0];
var box = document.getElementById("box");
var apple = document.getElementById("apple");
var score = document.getElementById("score").getElementsByTagName("span")[0];
var level = document.getElementById("score").getElementsByTagName("span")[1];
var gameOver;
var square = 20;
var dirArr = {
left: { name: "left", key: 65, point: { x: -1, y: 0 }, img: "left.png" },
right: { name: "right", key: 68, point: { x: 1, y: 0 }, img: "right.png" },
up: { name: "up", key: 87, point: { x: 0, y: -1 }, img: "up.png" },
down: { name: "down", key: 83, point: { x: 0, y: 1 }, img: "down.png" }
};
var dirList = [];
var currentDir = dirArr["right"];
document.onkeydown = function(event) {
var event = event || window.event;
addDirection(event.keyCode);
}
function addDirection(key) {
var dir;
// 获取方向
for (k in dirArr) {
if (dirArr[k].key == key) {
dir = dirArr[k];
}
}
if (!dir) {
return;
}
//获取上一次的方向
var lastDirection = dirList[dirList.length - 1];
if (!lastDirection) { lastDirection = currentDir }
if (lastDirection.name == dir.name) {
return;
} else if (lastDirection.point.x + dir.point.x == 0 && lastDirection.point.y + dir.point.y == 0) {
return;
}
if (dirList.length > 3) {
return;
}
dirList.push(dir);
}
function getDirection(arr) {
if (arr.length != 0) {
currentDir = arr.shift();
}
return currentDir;
}
function point(x, y) {
this.x = x;
this.y = y;
}
function move() {
//处理按键队列
var d = getDirection(dirList);
img.src = d.img;
//下一个要走的点
var pre = new point(head.offsetLeft + d.point.x * square, head.offsetTop + d.point.y * square);
//死亡判定机制
if (die(pre)) {
clearInterval(timer)
alert("GAME_OVER");
return;
}
//吃的机制
if (eat(pre)) {
console.log("eat");
}
//移动身子
for (var i = lis.length - 1; i > 0; i--) {
lis[i].style.left = lis[i - 1].offsetLeft + "px";
lis[i].style.top = lis[i - 1].offsetTop + "px";
}
head.style.left = pre.x + "px";
head.style.top = pre.y + "px";
}
var timer = setInterval(move, 300);
function die(p) {
var left = p.x;
var right = p.x + head.offsetWidth;
var toper = p.y;
var bottom = p.y + head.offsetHeight;
for (var i = 1; i < lis.length - 1; i++) {
if (left == lis[i].offsetLeft && toper == lis[i].offsetTop)
return 1;
}
if (left < 0 || toper < 0 || right > box.offsetWidth || bottom > box.offsetHeight) {
console.log(1)
return 1;
}
}
//初始化
for (var i = 0; i < lis.length; i++) {
lis[i].idx = i;
lis[i].style.left = -square * i + "px";
var backgroundColor = parseInt(255 * 255 * 255 * Math.random());
lis[i].style.backgroundColor = "#" + backgroundColor.toString(16);
}
//吃
function eat(p) {
if (p.x == apple.offsetLeft && p.y == apple.offsetTop) {
apple.style.left = 20 * Math.floor(Math.random() * 39) + "px";
apple.style.top = 20 * Math.floor(Math.random() * 29) + "px";
var li = document.createElement("li");
li.className = "heihei";
var backgroundColor = parseInt(255 * 255 * 255 * Math.random());
li.style.backgroundColor = "#" + backgroundColor.toString(16);
ul.appendChild(li);
score.innerHTML++;
clearInterval(timer);
var scoreLevel = Math.floor(score.innerHTML / 4);
level.innerHTML = scoreLevel + 1;
var timeLevel = scoreLevel > 7 ? 7 : scoreLevel;
timer = setInterval(move, 250 - timeLevel * 25);
}
}
}