一、案例演示
贪吃蛇游戏,利用面向对象思想绘制,实现吃到食物和碰到边界死亡功能。
二、知识点
面向对象编程、边界检测、吃掉食物后随机生成食物、吃到食物往蛇的尾巴加上一节
三、案例中的对象:食物、蛇、游戏对象
食物对象。
//创建数组用来保存每一个小方块食物
var elements = [];
食物的属性:所在位置、宽高度、颜色
function Food(x, y, width, height, color) {
//如果没有传入x值,则默认值为0
this.x = x || 0;
this.y = y || 0;
this.width = width || 20;
this.height = height || 20;
this.color = color || 'green';
}
通过原型设置初始化方法,实现随机产生食物对象,并渲染到map上。如果直接在Food的构造函数中写初始化方法,调用一次需要开辟一块内存,多次调用就要开辟多个内存。但在原型上添加方法则只需要开辟一次内存,节省了空间。
Food.prototype.init = function (map) {
// 随机食物的位置,map.宽度/food.宽度,总共有多少分food的宽度,随机一下。然后再乘以food的宽度
this.x = parseInt(Math.random() * map.offsetWidth / this.width) * this.width;
this.y = parseInt(Math.random() * map.offsetHeight / this.height) * this.height;
// 动态创建食物对应的div
var div = document.createElement('div');
map.appendChild(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;
elements.push(div);
}
当贪吃蛇吃到食物时,食物需要删除。 通过定义私有函数(外部不能访问)来删除食物
function remove() {
// elements数组中有这个食物(储存盒)
for(i = 0; i < elements.length; i++) {
var ele = elements[i];
// 删除页面上div
ele.parentNode.removeChild(ele);
// 删除elements数组中的元素
elements.splice(i, 1);
}
}
因此初始化init方法中应该调用remove方法。
通过自调用函数,进行封装,通过window暴露Food对象
//把Food暴露给window,外部可以使用
window.Food=Food;
蛇对象。
/创建数组存放小蛇的每个身体部分
var elements = [];
蛇的属性:蛇的宽高度、蛇的头部和身体、蛇运动的方向
function Snake(width, height, direction) {
// 设置每一个蛇节的宽度
this.width = width || 20;
this.height = height || 20;
// 蛇的每一部分, 第一部分是蛇头
this.body = [
{x: 3, y: 2, color: 'red'},
{x: 2, y: 2, color: 'black'},
{x: 1, y: 2, color: 'black'}
// {x: 0, y: 2, color: 'red'}
];
this.direction = direction || 'right';
}
通过原型设置初始化方法,把蛇渲染到map上 。
Snake.prototype.init = function(map) {
//删除原先的小蛇
remove();
//循环创建div
for(var i = 0; i < this.body.length; i++) {
//数组中的每一元素都是一个对象 obj
var obj = this.body[i];
var div = document.createElement('div');
map.appendChild(div);
div.style.left = obj.x * this.width + 'px';
div.style.top = obj.y * this.height + 'px';
div.style.position = "absolute";
div.style.backgroundColor = obj.color;
div.style.width = this.width + 'px';
div.style.height = this.height + 'px';
//把div加入到elements数组中--为了删除
elements.push(div)
}
}
通过原型添加move方法,让蛇动起来
Snake.prototype.move = function (food, map) {
// 让蛇身体的每一部分往前移动一下
var i = this.body.length - 1;
for(; 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 'left':
this.body[0].x -= 1;
break;
case 'right':
this.body[0].x += 1;
break;
case 'top':
this.body[0].y -= 1;
break;
case 'bottom':
this.body[0].y += 1;
break;
}
在移动的过程中判断蛇是否吃到食物,如果蛇头和食物的位置重合代表吃到食物。食物的坐标是像素,蛇的坐标是几个宽度,进行转换
var headX = this.body[0].x * this.width;
var headY = this.body[0].y * this.height;
if (headX === food.x && headY === food.y) {
// 吃到食物,往蛇节的最后加一节
var last = this.body[this.body.length - 1];
this.body.push({
x: last.x,
y: last.y,
color: last.color
})
// 把现在的食物对象删除,并重新随机渲染一个食物对象
food.init(map);
}
}
通过定义私有函数来删除蛇
function remove(){
// 获取数组
var i = elements.length - 1;
for(; i >= 0; i--) {
// 删除页面上渲染的蛇
elements[i].parentNode.removeChild(elements[i]);
// 删除elements数组中的元素
elements.splice(i, 1);
}
}
通过自调用函数,进行封装,通过window暴露Snake对象
window.Snake=Snake;
游戏对象。游戏对象用来管理游戏中的所有对象和开始游戏