1. 搭建页面
放一个容器盛放游戏场景 div#map,设置样式
#map {
width: 800px;
height: 600px;
background-color: #ccc;
position: relative;
}
2. 分析对象
- 游戏对象 Game
- 蛇对象 Snake
- 食物对象 Food
3. 创建食物对象
(1)创建 Food 的构造函数,并设置属性
(2)通过原型设置方法
- render 随机创建一个食物对象,并输出到 map 上
(3)通过自调用函数,进行封装,通过 window 暴露 Food 对象
4. 创建蛇对象
(1)创建 Snake 的构造函数,并设置属性
- width 蛇节的宽度 默认20
- height 蛇节的高度 默认20
- body 数组,蛇的头部和身体,第一个位置是蛇头
- direction 蛇运动的方向 默认right 可以是 left top bottom
(2)通过原型设置方法
- render 随机创建一个蛇对象,并输出到 map 上
(3)通过自调用函数,进行封装,通过 window 暴露 Snake 对象
5. 创建游戏对象
(1)创建 Game 的构造函数,并设置属性
(2)通过原型设置方法
- start 开始游戏(绘制所有游戏对象,渲染食物对象和蛇对象)
(3)通过自调用函数,进行封装,通过 window 暴露 Game 对象
6. 游戏逻辑1:写蛇的 move 方法
在蛇对象 (snake.js) 中,在 Snake 的原型上新增 move 方法
- 让蛇移动起来,把蛇身体的每一部分往前移动一下
- 蛇头部分根据不同的方向决定 往哪里
7. 游戏逻辑2:让蛇自己动起来
- 在 snake 中添加删除蛇的私有方法,在 render 中调用
- 在 game.js 中添加 runSnake 的私有方法,开启定时器调用蛇的 move 和 render 方法, 让蛇动起来
- 判断蛇是否撞墙
- 在 game.js 中添加 bindKey 的私有方法,通过键盘控制蛇的移动方向,在 start 方法中调 用 bindKey
8. 游戏逻辑3:判断蛇是否吃到食物
- 在 Snake 的 move 方法中判断在移动的过程中蛇是否吃到食物
- 如果蛇头和食物的位置重合代表吃到食物
- 食物的坐标是像素,蛇的坐标是几个宽度,需要进行转换
- 吃到食物,往蛇节的最后加一节
- 最后把现在的食物对象删除,并重新随机渲染一个食物对象
9. 其他处理1
- 把 html 中的 js 代码放到 index.js 中
- 避免 html 中出现 js 代码
10. 其他处理2
11. 其他处理3
自调用函数的参数
- 传入 window 对象:将来代码压缩的时候,可以吧 function (window) 压缩成 function (w)
- 传入 undefined
- 在将来会看到别人写的代码中会把 undefined 作为函数的参数(当前案例没有使用)
- 因为在有的老版本的浏览器中 undefined 可以被重新赋值,防止 undefined 被重新赋值
代码
1. HTML 代码
<!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>Document</title>
<link rel="stylesheet" href="css/index.css" />
</head>
<body>
<div class="map" id="map"></div>
<script src="js/index.min.js"></script>
</body>
</html>
2. CSS 代码
* {
margin: 0;
padding: 0;
}
.map {
position: relative;
width: 800px;
height: 800px;
background-color: lightgray;
}
3. JS 代码
(function (window, undefined) {
var Tools = {
getRandom: function (min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
},
getColor: function () {
var r = this.getRandom(0, 255);
var g = this.getRandom(0, 255);
var b = this.getRandom(0, 255);
return "rgb(" + r + "," + g + "," + b + ")";
},
};
window.Tools = Tools;
})(window, undefined);
(function (window, undefined) {
var ps = "absolute";
function Food(option) {
option = option instanceof Object ? option : {};
this.width = option.width || 20;
this.height = option.height || 20;
this.x = option.x || 0;
this.y = option.y || 0;
this.color = option.color || "green";
this.elements = [];
}
Food.prototype.render = function (map) {
var ele = document.createElement("div");
this.x = Tools.getRandom(0, map.clientWidth / this.width - 1) * this.width;
this.y =
Tools.getRandom(0, map.clientHeight / this.height - 1) * this.height;
ele.style.width = this.width + "px";
ele.style.height = this.height + "px";
ele.style.left = this.x + "px";
ele.style.top = this.y + "px";
ele.style.backgroundColor = this.color;
ele.style.position = ps;
map.appendChild(ele);
this.elements.push(ele);
};
Food.prototype.remove = function (map, i) {
map.removeChild(this.elements[i]);
this.elements.splice(i, 1);
};
window.Food = Food;
})(window, undefined);
(function (window, undefined) {
var ps = "absolute";
function Snake(option) {
option = option instanceof Object ? option : {};
this.width = option.width || 20;
this.height = option.height || 20;
this.body = [
{ x: 3, y: 2, color: "red" },
{ x: 2, y: 2, color: "blue" },
{ x: 1, y: 2, color: "blue" },
];
this.direction = "right";
this.elements = [];
}
Snake.prototype.render = function (map) {
for (var i = 0, len = this.body.length; i < len; i++) {
var piece = this.body[i];
var ele = document.createElement("div");
ele.style.width = this.width + "px";
ele.style.height = this.height + "px";
ele.style.left = piece.x * this.width + "px";
ele.style.top = piece.y * this.height + "px";
ele.style.position = ps;
ele.style.backgroundColor = piece.color;
map.appendChild(ele);
this.elements.push(ele);
}
};
Snake.prototype.move = 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;
}
var head = this.body[0];
switch (this.direction) {
case "right":
head.x += 1;
break;
case "left":
head.x -= 1;
break;
case "top":
head.y -= 1;
break;
case "bottom":
head.y += 1;
}
};
Snake.prototype.remove = function (map) {
for (var i = this.elements.length - 1; i >= 0; i--) {
map.removeChild(this.elements[i]);
}
this.elements = [];
};
window.Snake = Snake;
})(window, undefined);
(function (window, undefined) {
var that;
function Game(map) {
this.food = new Food();
this.snake = new Snake();
this.map = map;
that = this;
}
Game.prototype.start = function () {
this.food.render(this.map);
this.food.render(this.map);
this.food.render(this.map);
this.snake.render(this.map);
runSnake();
bindKey();
};
function bindKey() {
document.onkeydown = function (e) {
switch (e.keyCode) {
case 37:
that.snake.direction = "left";
break;
case 38:
that.snake.direction = "top";
break;
case 39:
that.snake.direction = "right";
break;
case 40:
that.snake.direction = "bottom";
break;
}
};
}
function runSnake() {
var timer = setInterval(function () {
that.snake.move();
that.snake.remove(that.map);
that.snake.render(that.map);
var maxX = that.map.offsetWidth / that.snake.width;
var maxY = that.map.offsetHeight / that.snake.height;
var headX = that.snake.body[0].x;
var headY = that.snake.body[0].y;
var hX = headX * that.snake.width;
var hY = headY * that.snake.height;
for (var i = 0; i < that.food.elements.length; i++) {
if (
that.food.elements[i].offsetLeft === hX &&
that.food.elements[i].offsetTop === hY
) {
that.food.remove(that.map, i);
that.food.render(that.map);
var last = that.snake.body[that.snake.body.length - 1];
that.snake.body.push({
x: last.x,
y: last.y,
color: last.color,
});
}
}
if (headX < 0 || headX >= maxX || headY < 0 || headY >= maxY) {
clearInterval(timer);
alert("Game over");
}
}, 150);
}
window.Game = Game;
})(window, undefined);
(function (window, undefined) {
var map = document.getElementById("map");
var game = new Game(map);
game.start();
})(window, undefined);
|