实现思路
1.创建一个包含宽度、高度、蛇移动方向、蛇组成(包含蛇头蛇尾)等属性以及包含绘制、移动等方法的蛇对象;
主要代码:
function Snake(options) {
options = options || {};
// 1. 属性
// 1.1 蛇节
this.width = options.width || 20;
this.height = options.height || 20;
// 1.2 蛇移动的方向
this.direction = options.direction || 'right';
// 1.3 蛇的身体和蛇头
this.body = [
{x: 2, y: 0, color: 'purple'}, // 蛇头
{x: 1, y: 0, color: 'red'}, // 蛇节
{x: 0, y: 0, color: 'red'} // 蛇节
];
}
Snake.prototype = {
constructor: Snake,
// 绘制
render: function (panel) {
// 1. 删除旧蛇
remove();
},
// 移动
move: function (food, panel) {
}
}
};
2.创建一个包含(用x,y坐标定义)位置、宽度高度、颜色等属性以及包含绘制方法的食物对象;
function Food(options) {
options = options || {};
// 1. 属性
this.x = options.x || 0;
this.y = options.y || 0;
this.width = options.width || 20;
this.height = options.height || 20;
this.color = options.color || 'red';
}
Food.prototype = {
constructor: Food,
// 绘制食物
render: function (panel) {
// 0. 绘制之前先删除
remove();
// 1. 随机位置
this.x = _.random(0, panel.clientWidth/this.width - 1) * this.width;
this.y = _.random(0, panel.clientHeight/this.height - 1) * this.height;
// console.log(panel.clientWidth, this.width);
// 2. 动态创建食物div
var div = document.createElement('div');
div.style.position = 'absolute';
div.style.top = this.y + 'px';
div.style.left = this.x + 'px';
div.style.width = this.width + 'px';
div.style.height = this.height + 'px';
div.style.backgroundColor = this.color;
div.style.borderRadius = this.width * 0.5 + 'px';
panel.appendChild(div);
foodArr.push(div);
}
};
3.在蛇的绘制方法中依照定义的蛇的属性去绘制小蛇(包含蛇头以及蛇尾位置,宽度高度,颜色等),注意:绘制前先要删除掉旧蛇。定义蛇的移动方法包含蛇头和蛇身,起到灵魂作用的是蛇头,用它控制了蛇的移动方向(上:蛇头y坐标-1,下:蛇头y坐标+1,左:蛇头x坐标-1,右:蛇头x坐标+1)蛇身(当前蛇节移动到上一个蛇节的位置即可)
Snake.prototype = {
constructor: Snake,
// 绘制
render: function (panel) {
// 1. 删除旧蛇
remove();
// 2. 绘制新蛇
for (var i = 0, len = this.body.length; i < len; i++) {
// 1. 取出蛇的信息
var obj = this.body[i];
// 2. 创建蛇节和蛇头
var div = document.createElement('div');
div.style.position = 'absolute';
div.style.left = obj.x * this.width + 'px';
div.style.top = obj.y * this.height + 'px';
div.style.width = this.width + 'px';
div.style.height = this.height + 'px';
div.style.backgroundColor = obj.color;
div.style.borderRadius = this.width * 0.5 + 'px';
panel.appendChild(div);
// 记录当前的蛇
snakeArr.push(div);
}
},
// 移动
move: function (food, panel) {
// 1. 控制蛇的身体移动 (当前的蛇节 移动到 上一个蛇节的位置)
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;
}
// 2. 控制蛇头的移动
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;
break;
}
}
};
5.单独拎出一个Game文件去管理蛇对象以及食物对象,定义Game对象包含食物属性(动态创建食物对象)蛇属性(动态创建蛇对象),并在Game原型定义绘制方法(分别绘制蛇对象和食物对象到面板上的方法)和移动方法(执行蛇移动+方向控制方法)
function Game(panel) {
this.food = new Food({});
this.snake = new Snake({});
this.panel = panel;
// console.log(this);
// 指针赋值
self = this;
}
Game.prototype = {
constructor: Game,
render: function () {
// 1.把食物和蛇绘制到面板上
this.food.render(this.panel);
this.snake.render(this.panel);
},
run: function () {
// 1. 蛇移动起来
snakeMove();
// 2. 方向控制
dirControl();
}
};
6.Game文件中定义蛇移动(设置一个定时器固定多长时间变化一次并在此方法中进行边界判断)和方向控制(利用键盘事件)的方法
function snakeMove(){
var timeId = setInterval(function () {
// 1. 蛇开始移动和绘制
self.snake.move(self.food, self.panel);
self.snake.render(self.panel);
// 2. 边界控制
var maxX = self.panel.clientWidth / self.snake.width;
var maxY = self.panel.clientHeight / self.snake.height;
// 2.1 获取蛇头的X和Y
var headX = self.snake.body[0].x;
var headY = self.snake.body[0].y;
// 2.2 水平判断
if(headX < 0 || headX >= maxX){
clearInterval(timeId);
if(confirm('很遗憾, 您输了!再来一次?')){
// 刷新界面
window.location.reload();
}else {
window.close();
}
}
// 2.3 垂直判断
if(headY < 0 || headY >= maxY){
clearInterval(timeId);
if(confirm('很遗憾, 您输了!再来一次?')){
// 刷新界面
window.location.reload();
}else {
window.close();
}
}
}, 200);
}
function dirControl(){
document.addEventListener('keydown', function (e) {
// console.log(e['keyCode']);
/*
37 - left
38 - top
39 - right
40 - bottom
*/
switch (e['keyCode']) {
case 37:
self.snake.direction = 'left';
break;
case 38:
self.snake.direction = 'top';
break;
case 39:
self.snake.direction = 'right';
break;
case 40:
self.snake.direction = 'bottom';
break;
}
}, false);
}
7.在蛇的移动过程中,注意蛇头是否与食物重叠坐标重叠的判断,如果重叠则让蛇增加一节并再生成一个随机位置的食物
move: function (food, panel) {
// 1. 控制蛇的身体移动 (当前的蛇节 移动到 上一个蛇节的位置)
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;
}
// 2. 控制蛇头的移动
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;
break;
}
// 3. 判断蛇头是否和食物的坐标重叠
var headX = head.x * this.width;
var headY = head.y * this.height;
// console.log(food.x, food.y);
// console.log(headX, headY);
if (headX === food.x && headY === food.y) {
// 3.1 让蛇增加一节
var last = this.body[this.body.length - 2];
this.body.push({
x: last.x,
y: last.y,
color: last.color
});
// 3.2 随机在面板上重新生成食物
food.render(panel);
}
}
};
完整实现github:github.com/missyouzi/t…