1,搭建页面模块
蛇和食物都是存在于map中,所以要相对于map对象来定位 子绝父相;
#map {
width: 800px;
height: 600px;
background: rgb(155, 150, 110);
position: relative;
margin: 20px 20px;
}
<div id="map">
</div>
食物对象
1,先定义食物的属性和方法
属性
坐标(x y)
颜色
宽
高
方法
render
随机在map中显示食物
函数
删除食物的函数
(function() {
//全局变量
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";
}
let map = document.getElementById("map");
console.log(map.offsetWidth)
console.log(map.offsetHeight)
//食物的原型方法
Food.prototype.render = function(map) {
//调用删除方法remove()
remove();
//生成随机的食物=>生成随机的食物对象的x,y tools方法不能用
// this.x = Math.floor(Math.random() * ((map.offsetWidth / this.width - 1) * this.width));
// this.y = Math.floor(Math.random() * ((map.offsetHeight / this.height - 1) * this.height));
//console.log(map.offsetWidth);
//console.log(map.offsetHeight);
this.x = Tools.getRandom(0, map.offsetWidth / this.width - 1) * this.width;
this.y = Tools.getRandom(0, map.offsetHeight / this.height - 1) * this.height;
//console.log(this.x)
//console.log(this.y);
let div = document.createElement('div');
map.appendChild(div);
//将食物发到数组中来
elements.push(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;
//将div食物放到map中
}
//删除食物
function remove() {
for (var i = elements.length - 1; i >= 0; i--) {
//删除食物
elements[i].parentNode.removeChild(elements[i]);
//删除数组中的食物
//splice方法传两个参数 第一个从什么位置删除 第二个删除几个
elements.splice(i, 1);
}
}
window.Food = Food
})()
创建蛇对象
snake
属性
width
height
body 数组
蛇头 蛇身
direction 运动方向
方法
render
函数 remove删除蛇 move移动
//开启新的局部作用域
(function() {
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'
}
]
}
//蛇的原型方法
Snake.prototype.render = function(map) {
//调用删除以前的蛇
remove();
//把每一个蛇节加蛇头渲染到map
//i = 0, len = this.body.length 只加载一次 提高效率
for (var i = 0, len = this.body.length; i < len; i++) {
//蛇头加蛇节
let object = this.body[i];
let div = document.createElement('div');
map.appendChild(div);
//记录创建的蛇
elements.push(div);
div.style.position = position;
div.style.width = this.width + 'px';
div.style.height = this.height + 'px';
div.style.left = object.x * this.width + 'px'
div.style.top = object.y * this.height + 'px'
div.style.backgroundColor = object.color;
}
}
//删除以前产生的蛇对象
//用到着的循环
function remove() {
for (var i = elements.length - 1; i >= 0; i--) {
elements[i].parentNode.removeChild(elements[i]);
elements.splice(i, 1);
}
}
//控制蛇移动的方法 参数food
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 也可以用if
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;
}
//判断蛇头是否和食物的坐标重合
var headx = head.x * this.width;
var heady = head.y * this.height;
if (headx == food.x && heady == food.y) {
//蛇增加一节
//获得设定最后一节
let last = this.body[this.body.length - 1];
this.body.push({
x: last.x,
y: last.y,
color: last.color
});
//在生成一个食物
food.render(map);
}
}
window.Snake = Snake;
})()
创建游戏对象
属性
蛇对象
食物对象
map
方法
start方法开始游戏
函数
bindKey() 键盘获取
runSnake()蛇的移动
(function() {
//定义Game对象允许该作用域中可以访问
var that;
function Game(map) {
//游戏属性
this.food = new Food();
this.snake = new Snake();
this.map = map;
//允许在该作用域中访问Game
that = this;
}
//定义开始游戏的原型方法
Game.prototype.start = function() {
//将食物和蛇渲染到map中去
this.food.render(this.map);
this.snake.render(this.map);
//调用蛇运动方法
runSnake();
bindKey()
//测试调用move方法
// this.snake.move();
// this.snake.render(this.map);
// this.snake.move();
// this.snake.render(this.map);
// this.snake.move();
// this.snake.render(this.map);
}
//通过键盘来控制蛇的移动方向
function bindKey() {
//document.onkeydown = function(e)
document.addEventListener('keydown', (e) => {
//获取键盘码
// console.log(e.keyCode);
//37==left 38==top 39==right 40==bottom
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;
}
}, false);
}
//定义蛇运动的方法 定时器
function runSnake() {
var timerId = setInterval(function() {
//在定时器中的this是指向window对象的
//获取游戏对象的蛇属性
this.snake.move(this.food, this.map);
this.snake.render(this.map);
//遇到边界停下来
let headX = this.snake.body[0].x;
let headY = this.snake.body[0].y;
let maxX = this.map.offsetWidth / this.snake.width;
let maxY = this.map.offsetHeight / this.snake.height;
//判断
if (headX < 0 || headX >= maxX) {
alert('Game Over')
clearInterval(timerId);
}
if (headY < 0 || headY >= maxY) {
alert('Game Over')
clearInterval(timerId);
}
}.bind(that), 150)
}
window.Game = Game;
})()
调用主方法
(function() {
var map = document.getElementById("map");
var game = new Game(map);
game.start();
})()
加载js文件的先后顺序,如果a依赖于b,b就先加载,
<script src="js/tool.js"></script>
<script src="js/food.js"></script>
<script src="js/snake.js"></script>
<script src="js/game.js"></script>
<script src="js/main.js"></script>
自调用函数
(function(){
})()
自调用函数中传入window和undefined
window的目的是让变量名能压缩
undefined 在老版本中的浏览器中,undefined 是可以被重新赋值
全局作用域下的代码。在其他js中是可以访问的
所以用自调用
开启一个新的作用域,避免命名冲突,进行代码优化
附带源代码
https://download.youkuaiyun.com/download/qq_45335128/12000267