JS实现的简易贪吃蛇
JS实现的简易贪吃蛇
贪吃蛇的html&css部分
<body>
<div class="main">
<button id="btn">开始游戏</button>
<div id="score"><span>分数:0</span></div>
<div id="map"></div>
</div>
<style>
.body {
padding: 0;
margin: 0;
}
.main {
width: 800px;
height: 400px;
margin: 50px auto;
}
#btn {
width: 100px;
height: 50px;
border: 1px solid black;
border-radius: 25px;
outline: none;
background: rgb(12, 93, 185);
float: left;
font-size: 15px;
cursor: pointer;
}
#btn:hover {
background: lightblue;
}
#score {
width: 100px;
height: 50px;
border: 1px solid black;
border-radius: 25px;
background: rgb(12, 93, 185);
box-sizing: border-box;
float: left;
line-height: 50px;
text-align: center;
font-size: 15px;
}
#map {
width: 800px;
height: 400px;
border: 1px solid black;
position: relative;
top: 50px;
background: url(https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1551100823778&di=cf00640008897d8eda5e6cd2304cf987&imgtype=0&src=http%3A%2F%2Fi0.hdslb.com%2Fvideo%2F5f%2F5f96e93363ccbf8a726924c77aea0001.jpg);
background-size: cover;
background-position-y: -10px;
}
</style>
</body>
简单的排版,这里就不细讲。
js部分
- 首先创建一个对象Snake
设置三个属性,宽高和初始蛇的坐标。
var map = document.getElementById('map');//全局声明
function Snake() {
this.width = 20;
this.height = 20;
this.derection = 'right';
this.body = [{ //蛇头
x: 2,
y: 0
// flag:'div'
}, { //蛇身
x: 1,
y: 0
}, { //蛇尾
x: 0,
y: 0
}];
}
- 在Snake对象继续添加方法
添加一个display方法,让蛇显示出来。
在全局声明里先实例化Snake,然后选中snake里的display()。
var snake=new Snake();
snake.display();
this.display = function () {
for (var i = 0; i < this.body.length; i++) {
var s = document.createElement('div');
this.body[i].flag = s;
s.style.width = this.width + 'px';
s.style.height = this.height + 'px';
s.style.background = 'black';//蛇身颜色
this.body[0].flag.style.background = 'red';//蛇头颜色
s.style.position = 'absolute';
s.style.left = this.body[i].x * this.width + 'px';
s.style.top = this.body[i].y * this.height + 'px';
map.appendChild(s);
}
}
- 让蛇跑起来,继续在Snake对象里面添加方法。
蛇头的移动通过方向属性判断,蛇身的移动可以通过前一节蛇身的坐标赋给当前这一节的蛇身来实现。坐标改变之后,删除旧的蛇的display,生成新的蛇的display。
this.run = function () {
for (var i = this.body.length - 1; i > 0; i--) {
this.body[i].x = this.body[i - 1].x;
this.body[i].y = this.body[i - 1].y;
} //蛇身前进1
switch (this.derection) {
case 'right':
this.body[0].x += 1;
break;
case 'left':
this.body[0].x -= 1;
break;
case 'up':
this.body[0].y -= 1;
break;
case 'down':
this.body[0].y += 1;
break;
}
for (var i = 0; i < this.body.length; i++) {
map.removeChild(this.body[i].flag);
} //删除原先的蛇
this.display(); //生成新的蛇
}
- 设置计时器
var timer;
document.getElementById('btn').onclick = function () {
timer = setInterval(function () {
snake.run();
}, 200)
}
- 设置按键事件
为了防止反方向移动,先给个if判断方向。在case里面设置计时器是为了防止按键点击过快出现的反方向通过自己蛇身的bug。
document.onkeydown = function () {
switch (window.event.keyCode) {
case 37:
if (snake.derection != 'right') {
setTimeout(function () {
snake.derection = 'left';
}, 200)
}
break;
case 38:
if (snake.derection != 'down') {
setTimeout(function () {
snake.derection = 'up';
}, 200)
}
break;
case 39:
if (snake.derection != 'left') {
setTimeout(function () {
snake.derection = 'right';
}, 200)
}
break;
case 40:
if (snake.derection != 'up') {
setTimeout(function () {
snake.derection = 'down';
}, 200)
}
break;
}
}
- 创建Food对象
全局声明:
var food=new Food();
food.display();
function Food() {
this.width = 20;
this.height = 20;
var f = document.createElement('div');
this.flag = f;
this.display = function () {
f.style.width = this.width + 'px';
f.style.height = this.height + 'px';
f.style.background = 'orange';
var isonsnake = true;
while (isonsnake) {//判断如果食物生成在蛇身上,则重新生成。
isonsnake = false;
this.x = Math.floor(Math.random() * 40);
this.y = Math.floor(Math.random() * 20);
for (var i = 0; i < snake.body.length; i++) {
if (this.x == snake.body[i].x && this.y == snake.body[i].y) {
isonsnake = true;
break;
}
}
}
f.style.position = 'absolute';
f.style.left = this.x * this.width + 'px';
f.style.top = this.y * this.height + 'px';
map.appendChild(f);
}
}
- 在snake.run()里面添加吃到食物的判断
吃到食物,用.push方法在蛇身坐标尾部添加元素,当蛇继续移动的时候,最后一节有了上一节的坐标,就能显示出来了。
//吃到food
if (this.body[0].x == food.x && this.body[0].y == food.y) {
this.body.push({
x: null,
y: null,
flag: null
})
map.removeChild(food.flag);
food.display();
}
这时候运行的时候会不断出现报错,这是为什么呢?
原来在下面这段代码中,.removeChild方法是用来清除节点,但是不能清除null。所以运行的时候浏览器一直报错。这时我们只要加一个if判断就能解决这个问题了。
for (var i = 0; i < this.body.length; i++) {
map.removeChild(this.body[i].flag);
}
将代码改为:
for (var i = 0; i < this.body.length; i++) {
if (this.body[i].flag != null) {
map.removeChild(this.body[i].flag);
}
}
- 在snake.run()里面添加撞墙以及撞到自己的判定
//reset
this.reset = function () {
for (var i = 0; i < this.body.length; i++) {
if (this.body[i].flag != null) {
map.removeChild(this.body[i].flag);
}
} //删除原先的蛇
this.derection = 'right';
this.body = [{ //蛇头
x: 2,
y: 0
// flag:'div'
}, { //蛇身
x: 1,
y: 0
}, { //蛇尾
x: 0,
y: 0
}];
this.display();
}
//判断是否出界
if (this.body[0].x < 0 || this.body[0].x > 39 || this.body[0].y < 0 || this.body[0].y > 29) {
clearInterval(timer);
alert('撞墙了!');
this.reset();
}
//判断是否撞到自己
for (var i = 4; i < this.body.length; i++) {
if (this.body[0].x == this.body[i].x && this.body[0].y == this.body[i].y) {
clearInterval(timer);
alert('撞到自己了!');
this.reset();
}
}
- 在吃到食物里面添加计分模块
全局声明:
var score=0;
reset方法也要做相应的更改
//吃到food
if (this.body[0].x == food.x && this.body[0].y == food.y) {
// debugger;
this.body.push({
x: null,
y: null,
flag: null
});
//记录分数
score += 1;
var sp = document.getElementsByTagName('span')[0];
sp.innerHTML = '分数:' + score;
map.removeChild(food.flag);
food.display();
}
//reset
this.reset = function () {
for (var i = 0; i < this.body.length; i++) {
if (this.body[i].flag != null) {
map.removeChild(this.body[i].flag);
}
}
this.body = [{
x: 2,
y: 0
}, {
x: 1,
y: 0
}, {
x: 0,
y: 0
}]
score = 0;
var sp = document.getElementsByTagName('span')[0];
sp.innerHTML = '分数:' + score;
this.direction = 'right';
this.display();
}
- 最后贴上全部代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>贪吃蛇</title>
</head>
<body>
<div class="main">
<button id="btn">开始游戏</button>
<div id="score"><span>分数:0</span></div>
<div id="map"></div>
</div>
<style>
.body {
padding: 0;
margin: 0;
}
.main {
width: 800px;
height: 400px;
margin: 50px auto;
}
#btn {
width: 100px;
height: 50px;
border: 1px solid black;
border-radius: 25px;
outline: none;
background: rgb(12, 93, 185);
float: left;
font-size: 15px;
cursor: pointer;
}
#btn:hover {
background: lightblue;
}
#score {
width: 100px;
height: 50px;
border: 1px solid black;
border-radius: 25px;
background: rgb(12, 93, 185);
box-sizing: border-box;
float: left;
line-height: 50px;
text-align: center;
font-size: 15px;
}
#map {
width: 800px;
height: 400px;
border: 1px solid black;
position: relative;
top: 50px;
background: url(https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1551100823778&di=cf00640008897d8eda5e6cd2304cf987&imgtype=0&src=http%3A%2F%2Fi0.hdslb.com%2Fvideo%2F5f%2F5f96e93363ccbf8a726924c77aea0001.jpg);
background-size: cover;
background-position-y: -10px;
}
</style>
</body>
<script>
var map = document.getElementById('map');
var timer;
var score = 0;
var snake = new Snake();
var food = new Food();
snake.display();
food.display(); //初始化显示
document.getElementById('btn').onclick = function () {
clearInterval(timer);
timer = setInterval('snake.run()', 100);
}
function Snake() {
this.width = 10;
this.heigh = 10;
this.direction = 'right';
this.body = [{
x: 2,
y: 0
}, {
x: 1,
y: 0
}, {
x: 0,
y: 0
}]
//reset
this.reset = function () {
for (var i = 0; i < this.body.length; i++) {
if (this.body[i].flag != null) {
map.removeChild(this.body[i].flag);
}
}
this.body = [{
x: 2,
y: 0
}, {
x: 1,
y: 0
}, {
x: 0,
y: 0
}]
score = 0;
var sp = document.getElementsByTagName('span')[0];
sp.innerHTML = '分数:' + score;
this.direction = 'right';
this.display();
}
//displag snake
this.display = function () {
for (var i = 0; i < this.body.length; i++) {
var s = document.createElement('div');
this.body[i].flag = s;
s.style.width = this.width + 'px';
s.style.height = this.heigh + 'px';
s.style.background = 'black';
this.body[0].flag.style.background = 'red';
s.style.position = 'absolute';
s.style.top = this.body[i].y * this.width + "px";
s.style.left = this.body[i].x * this.width + 'px';
map.appendChild(s);
}
}
//running snake
this.run = function () {
for (var i = this.body.length - 1; i > 0; i--) {
this.body[i].x = this.body[i - 1].x;
this.body[i].y = this.body[i - 1].y;
} //蛇身
switch (this.direction) {
case 'right':
this.body[0].x += 1;
break;
case 'left':
this.body[0].x -= 1;
break;
case "up":
this.body[0].y -= 1;
break;
case "down":
this.body[0].y += 1;
break;
} //蛇头
//判断是否出界
if (this.body[0].x < 0 || this.body[0].x > 79 || this.body[0].y < 0 || this.body[0].y > 39) {
clearInterval(timer);
alert('撞墙了!');
this.reset();
return false;
}
//判断是否撞到自己
for (var i = 4; i < this.body.length; i++) {
if (this.body[0].x == this.body[i].x && this.body[0].y == this.body[i].y) {
clearInterval(timer);
alert('撞到自己了!');
this.reset();
return false;
}
}
//吃到food
if (this.body[0].x == food.x && this.body[0].y == food.y) {
// debugger;
this.body.push({
x: null,
y: null,
flag: null
});
//记录分数
score += 1;
var sp = document.getElementsByTagName('span')[0];
sp.innerHTML = '分数:' + score;
map.removeChild(food.flag);
food.display();
}
for (var i = 0; i < this.body.length; i++) {
if (this.body[i].flag != null) {
map.removeChild(this.body[i].flag);
}
}
this.display();
}
}
function Food() {
this.width = 10;
this.height = 10;
this.display = function () {
var isonsnake = true;
while (isonsnake) {
isonsnake = false;
this.x = Math.floor(Math.random() * 80);
this.y = Math.floor(Math.random() * 40);
for (var i = 0; i < snake.body.length; i++) {
if (this.x == snake.body[i].x && this.y == snake.body[i].y) {
isonsnake = true;
break;
}
}
}
var f = document.createElement('div');
this.flag = f;
f.style.width = this.width + 'px';
f.style.height = this.height + 'px';
f.style.background = 'orange';
f.style.position = 'absolute';
f.style.top = this.width * this.y + 'px';
f.style.left = this.width * this.x + 'px';
map.appendChild(f);
}
}
//添加按键事件
document.body.onkeydown = function () {
switch (window.event.keyCode) {
case 37:
if (snake.direction != 'right') {
setTimeout(function () {
snake.direction = 'left';
}, 100);
}
break;
case 38:
if (snake.direction != 'down') {
setTimeout(function () {
snake.direction = 'up';
}, 100);
}
break;
case 39:
if (snake.direction != 'left') {
setTimeout(function () {
snake.direction = 'right';
}, 100);
}
break;
case 40:
if (snake.direction != 'up') {
setTimeout(function () {
snake.direction = 'down';
}, 100);
}
break;
}
}
</script>
</html>