随着学习的慢慢深入,对JS的了解也在慢慢一点一点的增加,第一次真正的体会到了JS的基于面向对象的编程,虽然JS只是一种脚本语言,但功能还是很强大的,经过这次的JS贪吃蛇编程,让我对编程语言有了更深一步的认识,编程并不是你会的语言越多越好,而是对一门语言深入进去,其他的都是大同小异,也渐渐的认识到了,编程最重要的还是自己解决问题的思路,当思路有了,一切的问题都是小问题,我这个游戏虽然是最简单的贪吃蛇游戏,但我自己从中也学到了很多的知识,认识到了很多的问题。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JS贪吃蛇</title>
<style type="text/css">
.map {
width: 800px;
height: 600px;
background-color: #ccc;
position: relative;//设置地图为相对定位
}
</style>
</head>
<body>
<div class="map" id="map">
</div>
<script type="text/javascript">
//食物的自调用函数
(function(){
var foodElements = [];//食物数组,用来保存每个小方块食物
//创建食物的构造函数
function Food(x,y,width,height,color){
//小方块食物的各项属性,设置默认值
this.x = x||0;
this.y = y||0;
this.width = width||20;
this.height = height||20;
this.color = color||"green";
}
//为Food原型添加初始化方法,将食物添加到地图里
Food.prototype.init = function(map){
removeFood();
//传入map地图,确定食物要显示在那张地图里
//创建食物
var foodDiv = document.createElement("div");
//将食物添加到地图map里
map.appendChild(foodDiv);
//为食物盒子设置样式
foodDiv.style.width = this.width + "px";
foodDiv.style.height = this.height + "px";
foodDiv.style.backgroundColor = this.color;
//随机产生食物盒子的横纵坐标,食物盒子的横纵坐标是随机产生的,不应当是固定的
this.x = parseInt(Math.random()*(map.offsetWidth/this.width))*this.width;
this.y = parseInt(Math.random()*(map.offsetHeight/this.height))*this.height;
foodDiv.style.left = this.x + "px";
foodDiv.style.top = this.y + "px";
//食物盒子在map地图中,应当是浮动的,将食物盒子设置为绝对定位
foodDiv.style.position = "absolute";
//将创建好的食物添加到食物数组foodElements中
foodElements.push(foodDiv);
};
//将Food构造函数挂到window中,以便外部可以直接调用
//食物的删除方法--私有函数,仅食物对象自己能调用
function removeFood(){
//利用map父节点删除foodDiv食物节点
for (var i = 0;i<foodElements.length;i++) {
//找到需要删除的子元素
var ele = foodElements[i];
//获取该子元素的父节点
ele.parentNode.removeChild(ele);
//<------以上仅将地图里的食物删除掉,还需将食物数组foodElements里的该元素也删除掉----->//
foodElements.splice(i,1);
}
}
window.Food = Food;
}());
//小蛇的自调用函数
(function(){
//小蛇的构造函数
var snakeElements = [];//存放小蛇的每个身体部分
function Snake(width,height,direction){
this.width = width||20;
this.height = height||20;
this.direction = direction||"right";
//创建数组用以存放小蛇的身体
this.snakeBody = [
{x:3,y:1,color:"red"},//蛇的头部
{x:2,y:1,color:"orange"},
{x:1,y:1,color:"orange"},
];
}
//小蛇的初始化方法,需反复调用,将这个初始化方法添加到原型对象里
Snake.prototype.init = function(map){//传入地图map,确定小蛇的位置
//每次移动时,均会重新绘制小蛇,所以需要在重新绘制之前将原来的小蛇删除掉,以形成小蛇移动的效果
removeSnake();
//循环遍历snakeElements数组,初始化小蛇的身体各个部分
for (var i = 0;i<this.snakeBody.length;i++) {
var obj = this.snakeBody[i];
//创建小蛇身体的各个部分,并将小蛇加入到地图map里
var snakeDiv = document.createElement("div");
map.appendChild(snakeDiv);
//设置小蛇身体的属性
snakeDiv.style.position = "absolute";
snakeDiv.style.width = this.width+"px";
snakeDiv.style.height = this.height+"px";
//小蛇的横纵坐标
snakeDiv.style.left = (obj.x*20)+"px";
snakeDiv.style.top = (obj.y*20)+"px";
snakeDiv.style.backgroundColor = obj.color;
//将创建好的小蛇身体添加到snakeElements数组里
snakeElements.push(snakeDiv);
}
//添加小蛇运动的方法
Snake.prototype.move = function (food,map){
var i = this.snakeBody.length - 1;
//改变蛇身体各个部分的横纵坐标
for (;i>0;i--) {
//for (;i<0;i--) :错误,for中的i<0为判断条件,当判断条件为i<0时,该循环永不执行
this.snakeBody[i].x = this.snakeBody[i-1].x;
this.snakeBody[i].y = this.snakeBody[i-1].y;
}
//判断方向改变小蛇头部的位置
switch(this.direction){
case "right":this.snakeBody[0].x+=1;break;
case "left":this.snakeBody[0].x-=1;break;
case "top":this.snakeBody[0].y-=1;break;
case "bottom":this.snakeBody[0].y+=1;break;
}
//判断有没有吃到食物
//小蛇的头的坐标和食物的坐标一致
var headX=this.snakeBody[0].x*this.width;
var headY=this.snakeBody[0].y*this.height;
//判断小蛇的头的坐标和食物的坐标是否相同
if(headX==food.x&&headY==food.y){
//获取小蛇的最后的尾巴
var snakeLast=this.snakeBody[this.snakeBody.length-1];
//把最后的蛇尾复制一个,重新的加入到小蛇的snakeBody中
this.snakeBody.push({
x:snakeLast.x,
y:snakeLast.y,
color:snakeLast.color
});
//把食物删除,重新初始化食物
food.init(map);
}
}
//小蛇的删除方法
function removeSnake(){
//在创建小蛇时,将小蛇添加到了snakeElements中,所以在删除小蛇时应当从保存小蛇的
//snakeElements数组中入手
var i = snakeElements.length-1;
for (;i>=0;i--) {
//小蛇对象存在与map对象中,所以在删除小蛇时,先找到小蛇身体对象的父级元素即:map
//然后再利用map对象删除这个小蛇的身体对象
var ele = snakeElements[i];
ele.parentNode.removeChild(ele);
//<------以上仅将地图里的小蛇删除掉,还需将食物数组snakeElements里的该元素也删除掉----->//
snakeElements.splice(i,1);
}
}
};
window.Snake = Snake;
}());
//游戏的自调用函数
(function(){
var that = null;
//游戏的构造函数
function Game(map){
this.food = new Food();
this.snake = new Snake();
this.map = map;
that = this;
};
//初始化游戏
Game.prototype.init = function(){
//食物初始化
this.food.init(this.map);
//小蛇初始化
this.snake.init(this.map);
//调用自动函数,让小蛇动起来
this.runSnake(this.food,this.map);
//调用按键的方法
this.bindKey();
};
//设置原型方法,让小蛇可以自动的运动起来
Game.prototype.runSnake = function (food, map) {
//自动的去移动
var timeId = setInterval(function () {
//此时的this是window
//移动小蛇
this.snake.move(food, map);
//初始化小蛇
this.snake.init(map);
//横坐标的最大值
var maxX = map.offsetWidth / this.snake.width;
//纵坐标的最大值
var maxY = map.offsetHeight / this.snake.height;
//小蛇的头的坐标
var headX = this.snake.snakeBody[0].x;
var headY = this.snake.snakeBody[0].y;
//横坐标
if (headX < 0 || headX >= maxX) {
//撞墙了,停止定时器
clearInterval(timeId);
alert("游戏结束");
}
//纵坐标
if (headY < 0 || headY >= maxY) {
//撞墙了,停止定时器
clearInterval(timeId);
alert("游戏结束");
}
}.bind(that), 150);
};
//添加原型方法---设置用户按键,改变小蛇移动的方向
Game.prototype.bindKey=function () {
//获取用户的按键,改变小蛇的方向,
//addEventListener为document对象绑定keydown事件
document.addEventListener("keydown",function (e) {
//这里的this应该是触发keydown的事件的对象---document,
//所以,这里的this就是document
//获取按键的值
switch (e.keyCode){
case 65:this.snake.direction="left";break;
case 87:this.snake.direction="top";break;
case 68:this.snake.direction="right";break;
case 83:this.snake.direction="bottom";break;
}
}.bind(that),false);
};
window.Game = Game;
}());
//初始化游戏对象
var gm = new Game(document.getElementById("map"));
//初始化游戏---开始游戏
gm.init();
</script>
</body>
</html>