贪吃蛇案例(面对对象)
案例目标
游戏的目的是用来体会js高级语法的使用,不需要具备抽象对象的能力,使用面向对象的方式分析问题,需要一个漫长的过程。
游戏实现后的图片
功能实现
搭建页面
放一个容器盛放游戏场景div#map
<div id="map">
</div>
设置样式
#map {
width: 800px;
height: 600px;
background-color: lightgray;
position: relative;
}
* {
margin: 0;
padding: 0;
}
分析对象
- 食物对象
- 蛇对象
- 游戏对象
Tools工具
创建随机数的工具,使用自调用函数,开启一个新的作用域,避免命名冲突,通过自调用函数,进行封装,通过window属性暴露Tools对象
(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; //[0,1) 10-1+1+1 random <10
// window.Tools = Tools;
},
};
window.Tools = Tools;
})(window, undefined)
创建食物对象
- food
- 属性
- x
- y
- width
- height
- color
- 方法
- render 随机创建一个食物对象,并渲染到map上
- 属性
- 创建Food的构造函数,并设置属性
用一个options对象作参数
// 局部作用域
var position = "absolute";
// 记录上次创建的食物,为删除做准备
var elements = [];
function Food(options) {
options = options || {};
this.x = options.x || 0;
this.y = options.y || 0;
this.width = options.width || 20;
this.height = options.height || 20;
this.color = options.color || "green";
}
- 通过原型设置render方法,实现随机产生食物对象,并渲染到map上
// 渲染
Food.prototype.render = function (map) {
// 删除之前创建的食物
remove();
// 随机设置x和y
this.x = Tools.getRandom(0, map.offsetWidth / this.width - 1) * this.width;
this.y = Tools.getRandom(0, map.offsetHeight / this.height - 1) * this.height;
// 动态创建div页面上显示的食物
var div = document.createElement("div");
map.appendChild(div);
elements.push(div);
// 设置div的样式
div.style.position = position;
div.style.left = this.x + "px";
div.style.top = this.y + "px";
div.style.width = this.width + "px";
div.style.height = this.height + "px";
div.style.backgroundColor = this.color;
};
- 删除食物方法
// 删除食物
function remove() {
// 倒着遍历,从最后一个开始删除
for (var i = elements.length - 1; i >= 0; i--) {
// 删除div
elements[i].parentNode.removeChild(elements[i]);
// 删除数组中的元素
// 删除数组元素
// 第一个参数,从哪个元素开始删除
// 第二个参数,删除几个元素
elements.splice(i, 1);
}
}
食物对象已经创建完成,可以测试一下是否有效果
var map = document.getElementById('map');
var food = new Food();
food.render(map);
创建蛇对象
- Snake
- 属性
- width 蛇节的宽度默认20
- height 蛇节的高度默认20
- body 数组,蛇的头部和身体,第一个位置是蛇头
- direction 蛇运动的方向,默认right 可以是left 、top、bottom
- 方法
- render 把蛇渲染到map上
- Snake构造函数
var position = 'absolute';
// 记录之前创建的蛇
var elements = [];
function Snake(options) {
options = options || {};
// 蛇节大小
this.width = options.width || 20;
this.height = options.height || 20;
// 蛇的方向
this.direction = options.direction || 'right';
// 蛇的身体
this.body = [
{ x: 3, y: 2, color: 'red' },
{ x: 2, y: 2, color: 'blue' },
{ x: 1, y: 2, color: 'blue' }
];
}
- render 方法
Snake.prototype.render = function (map) {
// 删除之前创建的蛇
remove();
// 把每一个蛇节渲染到地图上
for (var i = 0, len = this.body.length; i < len; i++) {
// 蛇节
var object = this.body[i];
var div = document.createElement('div');
map.appendChild(div);
elements.push(div);
// 设置div的样式
div.style.position = position;
div.style.left = object.x * this.width + "px";
div.style.top = object.y * this.height + "px";
div.style.width = this.width + "px";
div.style.height = this.height + "px";
div.style.backgroundColor = object.color;
}
}
- 删除蛇的方法
// 删除蛇的方法
function remove() {
for (var i = elements.length - 1; i >= 0; i--) {
// 删除div
elements[i].parentNode.removeChild(elements[i]);
// 删除数组中的元素
// 删除数组元素
// 第一个参数,从哪个元素开始删除
// 第二个参数,删除几个元素
elements.splice(i, 1);
}
}
- 控制蛇移动的方法
Snake.prototype.move = function (food, map) {
// 控制蛇的身体移动(当前蛇节到上一个蛇节的位置)
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 'bottom':
head.y += 1;
break;
case 'top':
head.y -= 1;
break;
case 'left':
head.x -= 1;
break;
}
// 2.4 当蛇遇到食物做相应的处理
var headX = head.x * this.width;
var headY = head.y * this.height;
if (headX === food.x && headY === food.y) {
// 1.让蛇增加一节
// 获取蛇的最后一节
var last = this.body[this.body.length - 1];
this.body.push({
x: last.x,
y: last.y,
color: last.color
})
// 2.随机在地图上重新生成食物
food.render(map);
var score = this.body.length - 3;
// console.log(this.body.length);
// console.log(score);
window.score = score;
// console.log(window);
// console.log(window.score);
}
// console.log(score);
}
测试代码是否正确
var snake = new Snake();
snake.render(map);
snake.move(food, map);
创建游戏对象
游戏对象用来管理游戏中所有的对象和开始游戏
- Game
- 属性
- food
- snake
- map
- 方法
- start 开始游戏(绘制所有游戏对象)
- 属性
- 构造函数
function Game(map) {
this.food = new Food();
this.snake = new Snake();
this.map = map;
that = this;
}
- 开始游戏,渲染食物对象和蛇对象
Game.prototype.start = function () {
// 1.把蛇和食物对象,渲染到地图上
this.food.render(this.map);
// this.snake.move(that.food, that.map);
this.snake.render(this.map);
// 2.开始游戏的逻辑
// 2.1让蛇移动起来
runSnake();
// 2.3通过键盘控制蛇移动的方向
bindKey();
}
- 控制蛇动起来
function runSnake() {
var timerId = setInterval(function () {
// 让蛇走一格
// 在定时器的function中this指向window对象的
this.snake.move(this.food, this.map);
this.snake.render(this.map);
// 2.2 当蛇遇到边界的时候游戏结束
// 获取蛇头的坐标
var maxX = this.map.offsetWidth / this.snake.width;
var maxY = this.map.offsetHeight / this.snake.height;
var headX = this.snake.body[0].x;
var headY = this.snake.body[0].y;
if (headX < 0 || headX >= maxX) {
clearInterval(timerId);
alert('游戏结束!分数是:' + window.score);
}
if (headY < 0 || headY >= maxY) {
clearInterval(timerId);
alert('游戏结束!分数是:' + window.score);
}
}.bind(that), 150)
}
- 通过键盘控制蛇移动的方向
// 通过键盘控制蛇移动的方向
function bindKey() {
// document.onkeydown = function () {
// };
document.addEventListener('keydown', function (e) {
// console.log(e.keyCode);
// 37 == left 38 == top 39 == right 40 == bottom
switch (e.keyCode) {
case 37:
this.snake.direction = 'left';
break;
case 65:
this.snake.direction = 'left';
break;
case 38:
this.snake.direction = 'top';
break;
case 87:
this.snake.direction = 'top';
break;
case 39:
this.snake.direction = 'right';
break;
case 68:
this.snake.direction = 'right';
break;
case 40:
this.snake.direction = 'bottom';
break;
case 83:
this.snake.direction = 'bottom';
break;
}
// bind 方法ES5中新增的方法
// 新建一个方法,bind中第一个参数可以改变函数中this的指向
// bind并没有调用方法
}.bind(that), false);
}
最后,测试代码
var map = document.getElementById('map');
var game = new Game(map);
game.start();
总结,面对对象编程,先将对象的属性和方法写出来,再渲染到地图上,可以自己再这个基础上多做些补充。
比如可以将食物的颜色发生变化,可以用Tools工具取rgb的随机数
或者提高游戏难度等等。。。。