JS实现贪吃蛇小游戏,效果图如下:
思路分析:
一、创建地图
1.封装一个地图类
function map() {
this._map = null; //封装接受地图对象的属性
this._span=null;
//创建地图的方法
this.createMap = function () {
if (this._map == null) {
this._map = document.createElement("div");
this._map.className = "map";
}
}
}
2.通过实例化调用类的属性和方法创建地图;
//实例化地图
Map = new map();
Map.createMap();
Map.createSpan();
二、创建蛇及其移动的方法
1.经典款贪吃蛇由若干个小方块组成身体,蛇头与蛇身的颜色不一致,但大小相同,即蛇是由很多属性一致的方块组成,要存储一系列类型一致的数据第一时间考虑数组,并且数组有push()追加方法,也解决了后面吃食物后身体增长的问题;默认蛇开始为3个小方块长度;(30x30的小方块)
说明:数组中存储left,top,颜色,null四个值
function snake() {
this._map = null;
this._span=null;
this.direct = "right"; //蛇的默认元素 x,y,颜色
this._snake = [[3, 1, "red", null], [2, 1, "yellow", null], [1, 1, "yellow", null]];
this.createSnake = function () {
for (var i = 0; i < this._snake.length; i++) {
if (this._snake[i][3] == null) {
this._snake[i][3] = document.createElement('div');
this._snake[i][3].style.backgroundColor = this._snake[i][2];
this._snake[i][3].className = "snake";
}
this._snake[i][3].style.left = this._snake[i][0] * 30 + "px";
this._snake[i][3].style.top = this._snake[i][1] * 30 + "px";
this._map.appendChild(this._snake[i][3]);
}
}
2.封装蛇移动方法
(1)贪吃蛇运动其实是属性(left,top)的传递,即蛇头移动后,其后那节身体移动到蛇头移动前的位置,再后面的身体依次移动到前一节移动前的位置;
需增加一个蛇头默认方向属性 this.direct = "right"; 控制蛇头在不同方向上的运动,带动蛇身体的移动;
在改变每节属性改变之后需再次调用蛇的创建方法,相当于每次移动后在新的位置创建蛇利用计时器;
this.snakeMove = function () {
//蛇的属性传递 x,y
var len = this._snake.length - 1;
for (var i = len; i > 0; i--) {
this._snake[i][0] = this._snake[i - 1][0];
this._snake[i][1] = this._snake[i - 1][1];
}
//设置蛇头在不同方向的移动 带动蛇的移动 需增加一个默认方向属性
switch (this.direct) {
case "right":
this._snake[0][0] += 1;
break;
case "left":
this._snake[0][0] -= 1;
break;
case "up":
this._snake[0][1] -= 1;
break;
case "down":
this._snake[0][1] += 1;
break;
}
(2)通过按键wsad控制蛇的上下左右移动
e.keyCode 获取按键码的方法 利用获取到的按键码控制上下左右移动;
注意:当蛇朝着一个方向正在运动的时候,按相反键时不能使蛇反向移动,需要处理这个bug;(在执行按键操作之前对现在的方向进行判断)
document.onkeypress = function (e) {
switch (e.key) {
case "w":
if (Snake.direct == "down")
return;
Snake.direct = "up";
break;
case "a":
if (Snake.direct == "right")
return;
Snake.direct = "left";
break;
case "d":
if (Snake.direct == "left")
return;
Snake.direct = "right";
break;
case "s":
if (Snake.direct == "up")
return;
Snake.direct = "down";
break;
}
}
(3)封装蛇的穿墙方法 即当蛇运到到边界令其从相反方向的边间穿出;
利用蛇头坐标值(left和top)与边界做比较,相等时设置蛇头的坐标为相反方向的边界值
注意:判断上下左右方向值,只需要改变相应坐标即可;
需要在蛇移动的方法中调用蛇穿墙方法
判断时可以使用方块个数值(垂直方向最多有30 个,水平方向20个),但是判断条件需要减1,使蛇出现在地图内侧
//封装蛇穿墙的方法
this.snakeBack = function () {
if (this._snake[0][0] > 29) {
this._snake[0][0] = 0;
}
if (this._snake[0][0] < 0) {
this._snake[0][0] = 29;
}
if (this._snake[0][1] >19) {
this._snake[0][1] = 0;
}
if (this._snake[0][1] < 0) {
this._snake[0][1] = 19;
}
};
3.创建食物的方法
(1).封装食物的类 随机位置创建食物
利用Math.random()的方法,随机产生食物,需要注意的是必须向下取整,保证食物出现在30*20的地图内,食物的大小与蛇大小相同30*30
function food() {
this._food = null;
this._map = null;
this.x = 0;
this.y = 0;
this.createFood = function () {
this.x = Math.floor(Math.random() * 30);
this.y = Math.floor(Math.random() * 20);
if (this._food == null) {
this._food = document.createElement("div");
this._food.className = "food";
}
this._food.style.left = this.x * 30 + "px";
this._food.style.top = this.y * 30 + "px";
this._map.appendChild(this._food);
}
}
(2)实例化食物,将蛇挂载在地图上
//函数调用 创建食物
CreateFood(Map._map);
function CreateFood(map) {
Food = new food();
Food._map = map;
Food.createFood();
}
(4)蛇吃食物
判断蛇的left top与豆豆的left top是否一致,一致时,重新创建随机食物,同时蛇身体数组追加一节;
if (this._snake[0][0] == Food.x && this._snake[0][1] == Food.y) {
//蛇数组追加
this._snake.push([
this._snake[this._snake.length - 1][0],
this._snake[this._snake.length - 1][1],
"yellow",
null
]);
//重新随机创建食物
Food.createFood();
}
4.蛇头与蛇身相撞,游戏结束,清除计时器, 在蛇移动时调用
//封装蛇撞死的方法
this.snakeBackDie = function () {
for (var i = 1; i < this._snake.length; i++) {
if (this._snake[0][0] == this._snake[i][0] && this._snake[0][1] == this._snake[i][1]) {
alert("游戏结束");
clearInterval(time);
}
}
}
完整代码:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
* {
margin: 0;
padding: 0;
}
.map {
width: 900px;
height: 600px;
background-color: black;
position: relative;
margin: 0 auto;
}
.snake {
width: 30px;
height: 30px;
position: absolute;
border: 1px solid deeppink;
box-sizing: border-box;
}
.food {
position: absolute;
width: 30px;
height: 30px;
border-radius: 50%;
background-color: greenyellow;
}
.score {
position: absolute;
display: block;
width: 500px;
right: 10px;
text-align: right;
top: 10px;
color: white;
font-size: 20px;
}
</style>
</head>
<body>
<script>
var Map;
var Snake;
var Food;
var score = 0;
var speed = 500;
var time;
var game = (function () {
/*1.创建地图*/
function map() {
this._map = null;
this._span = null;
this.createMap = function () {
if (this._map == null) {
this._map = document.createElement("div");
this._map.className = "map";
}
}
this.createSpan = function () {
if (this._span == null) {
this._span = document.createElement("span");
this._span.className = "score";
this._span.innerHTML = "总分:0";
}
this._map.appendChild(this._span);
}
}
function snake() {
this._map = null;
this._span = null;
this.direct = "right"; //蛇的默认元素 x,y,颜色
this._snake = [[3, 1, "red", null], [2, 1, "yellow", null], [1, 1, "yellow", null]];
this.createSnake = function () {
for (var i = 0; i < this._snake.length; i++) {
if (this._snake[i][3] == null) {
this._snake[i][3] = document.createElement('div');
this._snake[i][3].style.backgroundColor = this._snake[i][2];
this._snake[i][3].className = "snake";
}
this._snake[i][3].style.left = this._snake[i][0] * 30 + "px";
this._snake[i][3].style.top = this._snake[i][1] * 30 + "px";
this._map.appendChild(this._snake[i][3]);
}
};
this.snakeMove = function () {
//蛇的属性传递 x,y
var len = this._snake.length - 1;
for (var i = len; i > 0; i--) {
//通过传递蛇的left top值完成蛇的运动
this._snake[i][0] = this._snake[i - 1][0];
this._snake[i][1] = this._snake[i - 1][1];
}
//设置蛇头在不同方向的移动 带动蛇的移动 需增加一个默认方向属性
switch (this.direct) {
case "right":
this._snake[0][0] += 1;
break;
case "left":
this._snake[0][0] -= 1;
break;
case "up":
this._snake[0][1] -= 1;
break;
case "down":
this._snake[0][1] += 1;
break;
}
//调用蛇穿墙的方法
this.snakeBack();
//蛇吃食物
if (this._snake[0][0] == Food.x && this._snake[0][1] == Food.y) {
score += 100;
this._span.innerHTML = "总分:" + score + "分";
if (score == 500) {
speed -= 200;
}
this._snake.push([
this._snake[this._snake.length - 1][0],
this._snake[this._snake.length - 1][1],
"yellow",
null
]);
//食物换位置
Food.createFood();
}
//调用蛇撞死的方法
this.snakeBackDie();
//重新创建蛇
this.createSnake();
};
//封装蛇穿墙的方法
this.snakeBack = function () {
if (this._snake[0][0] > 29) {
this._snake[0][0] = 0;
}
if (this._snake[0][0] < 0) {
this._snake[0][0] = 29;
}
if (this._snake[0][1] >19) {
this._snake[0][1] = 0;
}
if (this._snake[0][1] < 0) {
this._snake[0][1] = 19;
}
};
//封装蛇撞死的方法
this.snakeBackDie = function () {
for (var i = 1; i < this._snake.length; i++) {
if (this._snake[0][0] == this._snake[i][0] && this._snake[0][1] == this._snake[i][1]) {
alert("游戏结束");
clearInterval(time);
}
}
}
}
function food() {
this._food = null;
this._map = null;
this.x = 0;
this.y = 0;
this.createFood = function () {
this.x = Math.floor(Math.random() * 30);
this.y = Math.floor(Math.random() * 20);
if (this._food == null) {
this._food = document.createElement("div");
this._food.className = "food";
}
this._food.style.left = this.x * 30 + "px";
this._food.style.top = this.y * 30 + "px";
this._map.appendChild(this._food);
}
}
function getMaps() {
Map = new map();
Map.createMap();
Map.createSpan();
//创建食物
CreateFood(Map._map);
//创建蛇 把map作为参数传进去 添加蛇
CreateSnake(Map._map, Map._span);
return Map._map;
}
function CreateFood(map) {
Food = new food();
Food._map = map;
Food.createFood();
}
function CreateSnake(map, span) {
Snake = new snake();
Snake._map = map;
Snake._span = span;
Snake.createSnake();
//蛇移动
time = setInterval(function () {
Snake.snakeMove();
}, speed);
document.onkeypress = function (e) {
switch (e.key) {
case "w":
if (Snake.direct == "down")
return;
Snake.direct = "up";
break;
case "a":
if (Snake.direct == "right")
return;
Snake.direct = "left";
break;
case "d":
if (Snake.direct == "left")
return;
Snake.direct = "right";
break;
case "s":
if (Snake.direct == "up")
return;
Snake.direct = "down";
break;
}
}
}
return {
SnakeMap: getMaps()
}
})
();
/*最后创建的元素显示到body页面*/
document.body.appendChild(game.SnakeMap);
</script>
</body>
</html>