前言
贪吃蛇游戏在我上小学的时候就接触了,当时只有一台诺基亚,每天无聊的时候就是玩贪吃蛇,回想当年,为了吃到每个球都是小心翼翼,看着蛇慢慢变长。每天都想着突破记录,达到最高分。 现在选择软件工程专业,突然就想能不能做出这个游戏来,不管做成什么样子。因为对web感兴趣,学习了js,开始了尝试。
项目准备阶段
- 软件使用的是vscode
- 创建好三个文件index.html,index.css,index.js
项目开始
第一步先搭建结构
使用html、css搭建好类似于屏幕的盒子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>贪吃蛇</title>
<link rel="stylesheet" href="./style/index.css">
</head>
<body>
<div id="main">
<div id="stage">
<div id="snake">
<div></div>
</div>
<div id="food">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
<div id="score-panle">
<div>
SCORE: <span id="score">0</span>
</div>
<div>
level: <span id="level">1</span>
</div>
</div>
</div>
<script src="./index.js"></script>
</body>
</html>
第二步对结构进行布局修饰
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font: bold 20px "Courier";
}
#main {
width: 360px;
height: 420px;
background-color: #b7d4a8;
margin: 100px auto;
border: 10px solid #000;
border-radius: 40px;
display: flex;
flex-flow: column;
justify-content: space-around;
align-items: center;
}
#main #stage {
width: 304px;
height: 304px;
border: 2px solid #000;
position: relative;
}
#main #stage #snake > div {
width: 10px;
height: 10px;
background-color: #000;
border: 1px solid #b7d4a8;
position: absolute;
}
#main #stage #food {
width: 10px;
height: 10px;
background-color: black;
border: 1px solid #b7d4a8;
position: absolute;
left: 40px;
top: 100px;
display: flex;
flex-flow: row wrap;
justify-content: space-between;
align-content: space-between;
}
#main #stage #food > div {
width: 4px;
height: 4px;
background-color: black;
transform: rotate(45deg);
}
#main #score-panle {
width: 300px;
display: flex;
justify-content: space-between;
align-items: space-between;
}
第三步js编写游戏
先从简单的部分开始:记分牌类
class ScorePanel {
score = 0;
level = 1;
scoreEle;
levelEle;
maxLevel;
upScore
constructor(maxLevel = 10, upScore = 10) {
this.scoreEle = document.getElementById("score")
this.levelEle = document.getElementById("level")
this.maxLevel = maxLevel
this.upScore = upScore
}
addScore() {
this.scoreEle.innerHTML = ++this.score + ""
if (this.score % this.upScore === 0) {
this.levelUp()
}
}
levelUp() {
if (this.level < this.maxLevel)
this.levelEle.innerHTML = ++this.level + ""
}
}
食物类
- 实现功能:
1. 获得食物的位置 2. 修改食物的位置
class Food {
element;
constructor() {
this.element = document.getElementById("food");
}
get X() {
return this.element.offsetLeft;
}
get Y() {
return this.element.offsetTop;
}
change() {
let top = Math.round(Math.random() * 29) * 10;
let left = Math.round(Math.random() * 29) * 10;
this.element.style.left = left + "px";
this.element.style.top = top + "px";
}
}
蛇类
- 实现功能
- 设置和获取头的位置
- 设置蛇的运动
- 蛇吃食物后变长
- 判断蛇有没有撞墙和有没有撞身体
- 设置蛇不能反向移动
class Snake {
head;
element;
bodies;
constructor() {
this.head = document.querySelector("#snake>div")
this.element = document.getElementById("snake")
this.bodies = this.element.getElementsByTagName("div")
}
get X() {
return this.head.offsetLeft
}
get Y() {
return this.head.offsetTop
}
set X(value) {
if (this.X === value) {
return
}
if (value < 0 || value > 290) {
throw new Error("蛇撞墙了")
}
if (this.bodies[1] && this.bodies[1].offsetLeft === value) {
if (value > this.X) {
value = this.X - 10
} else {
value = this.X + 10
}
}
this.moveBody()
this.head.style.left = value + "px"
this.checkHeadBody()
}
set Y(value) {
if (this.Y === value) {
return
}
if (value < 0 || value > 290) {
throw new Error("蛇撞墙了")
}
if (this.bodies[1] && this.bodies[1].offsetTop === value) {
if (value > this.Y) {
value = this.Y - 10
} else {
value = this.Y + 10
}
}
this.moveBody()
this.head.style.top = value + "px"
this.checkHeadBody()
}
addBody() {
this.element.insertAdjacentHTML("beforeend", "<div></div>")
}
moveBody() {
for (let i = this.bodies.length - 1; i > 0; i--) {
let X = this.bodies[i-1].offsetLeft;
let Y = this.bodies[i-1].offsetTop;
this.bodies[i].style.left = X + "px";
this.bodies[i].style.top = Y + "px";
}
}
checkHeadBody() {
for (let i = 1; i < this.bodies.length; i++) {
let bd = this.bodies[i]
console.log(bd.offsetTop);
console.log(bd.offsetLeft);
if (this.Y === bd.offsetTop && this.X === bd.offsetLeft) {
throw new Error("撞到自己了")
}
}
}
}
游戏控制类
- 实现功能
- 对蛇、食物、记分牌三个类的引用
- 控制游戏的开始和结束
- 获取用户键盘(如果键盘按的太快有bug)
- 让蛇一直在移动
- 对加分、升级、食物位置变化、蛇变长的调用
class GameControl {
snake = new Snake();
food = new Food();
scorePanel = new ScorePanel();
direction = ""
isLive = true
constructor() {
this.snake = new Snake()
this.food = new Food()
this.scorePanel = new ScorePanel(10, 8)
this.init()
}
init() {
document.addEventListener("keydown", this.keydownHandler.bind(this))
this.run()
}
keydownHandler(event) {
this.direction = event.key
}
run() {
let X = this.snake.X
let Y = this.snake.Y
switch (this.direction) {
case "ArrowUp":
case "Up":
Y -=10
break;
case "ArrowDown":
case "Down":
Y += 10
break;
case "ArrowLeft":
case "Left":
X -= 10
break;
case "ArrowRight":
case "Right":
X += 10
break;
}
this.checkEat(X, Y)
try {
this.snake.X = X
this.snake.Y = Y
} catch (e) {
alert(e.message + "GameOver")
this.isLive = false
}
this.isLive && setTimeout(this.run.bind(this), 300 - (this.scorePanel.level - 1) * 30)
}
checkEat(X, Y) {
if (X === this.food.X && Y === this.food.Y) {
this.food.change()
this.scorePanel.addScore()
this.snake.addBody()
}
}
}
let game = new GameControl()
game.init()
总结
该项目使用了一些ES6标准,但有些地方优化也不是很好。该项目是学习尚硅谷视频后制作的。 新手尝试,不足之处敬请谅解。欢迎大佬评论区指教指教。
|