<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.map{
width: 800px;
height: 600px;
background-color: #ccc;
position: relative;
}
</style>
</head>
<body>
<!-- 地图初始化 -->
<div class="map"></div>
<script>
// //函数的自调用1
// (function () {
// console.log("yoyoyo");
// })();
// //函数的自调用2
// (function () {
// console.log("哟,我是第二个")
// }());
// (function () {
// function Random() {
// }
// Random.prototype.getRandom=function (min,max) {
// return Math.floor(Math.random()*(max-min))+min;
// }
// window.Random=new Random();
// }())
// console.log("==============随机x坐标:");
// console.log(Random.getRandom(0,40));
// 函数的自调用---食物小方块的函数自调用
(function () {
// 声明一个存放食物的数组,以备后面删除食物
let elements=[];
//创建一个食物的构造函数
//食物有哪些特征和行为呢
//特征/属性:宽、高、背景色、横坐标、纵坐标
function Food(width,height,color,x,y) {
this.width=width || 20;
this.height=height || 20;
this.color=color || "green";
this.x=x || 0;
this.y=y || 0;
}
//食物有哪些行为
//行为/方法:可能需要共享,因此将这些方法放在构造函数的原型对象中实现共享,节省内存
//1.需要初始化的方法,否则无法在地图页面中显示
//因为是需要在地图中显示,因此需要参数map地图
Food.prototype.init=function (map) {
//在初始化之前先删除原来的
remove();
let dvObj=document.createElement("div");
dvObj.style.width=this.width+"px";
dvObj.style.height=this.height+"px";
dvObj.style.backgroundColor=this.color;
//食物需要随机动态显示,因此是脱标的
dvObj.style.position="absolute";
//xy的随机获取,可以用上一个随机构造函数
//也可以用下面这种============获取坐标刻度==========================再乘以每一个刻度坐标对应的宽度=====
// dvObj.style.left=parseInt(Math.random()*(map.offsetWidth/this.width))*this.width+"px";
// dvObj.style.top=parseInt(Math.random()*(map.offsetHeight/this.height))*this.height+"px";
this.x=parseInt(Math.random()*(map.offsetWidth/this.width))*this.width;
this.y=parseInt(Math.random()*(map.offsetHeight/this.height))*this.height;
dvObj.style.left=this.x+"px";
dvObj.style.top=this.y+"px";
map.appendChild(dvObj);
elements.push(dvObj);
}
//创建一个私有函数 --删除小方块食物的功能
//此时就需要用到elements数组--即通过里面的元素找到父级元素来删除子元素
function remove() {
for(let i=0;i<elements.length;i++){
let element=elements[i];
element.parentElement.removeChild(element);
//删除数组中的这个元素
elements.splice(i,1);
}
}
//这个构造函数在自调用函数内部,因为如果外部想要调用这个构造函数,需要用全局变量window
window.Food=Food;
}());
//小蛇的自调用函数
(function () {
//创建一个小蛇的元素数组
let elements=[];
//创建小蛇的构造函数
//把初始化的小蛇分成三个小方块
//第一个方块是蛇头,后面俩个是蛇的身体部分
//width和height是每个小方块的宽高,因为都是等宽等高
function Snake(width,height,direction) {
this.width=width || 20;
this.height=height || 20;
this.snakeBody=[
{x:3,y:2,color:"red"},
{x:2,y:2,color:"orange"},
{x:1,y:2,color:"orange"},
];
this.direction=direction || "right";
}
//给小蛇初始化方法
//因为需要在地图中显示,因此需要传入地图参数
Snake.prototype.init=function (map) {
remove();
//遍历小蛇的身体来创建每一块的div
for(let i=0;i<this.snakeBody.length;i++){
let snakeObj=this.snakeBody[i];
let divObj=document.createElement("div");
divObj.style.width=this.width+"px";
divObj.style.height=this.height+"px";
divObj.style.backgroundColor=snakeObj.color;
divObj.style.left=snakeObj.x * this.width+"px";
divObj.style.top=snakeObj.y * this.height+"px";
divObj.style.position="absolute";
map.appendChild(divObj);
//方向
//push进数组中
elements.push(divObj);
}
};
Snake.prototype.move=function (food,map) {
// 移动小蛇
// 小蛇的身体 和蛇头区分开
// 身体部分 移动都是后面一个拿前一个的坐标轴
let i=this.snakeBody.length-1;
for(;i>0;i--){
this.snakeBody[i].x=this.snakeBody[i-1].x;
this.snakeBody[i].y=this.snakeBody[i-1].y;
}
//头部-区分方向
switch(this.direction){
case 'left':
this.snakeBody[0].x-=1;
break;
case 'right':
this.snakeBody[0].x+=1;
break;
case 'top':
this.snakeBody[0].y-=1;
break;
case 'bottom':
this.snakeBody[0].y+=1;
break;
}
//吃到食物时候的处理
//即判定当前蛇头的坐标和食物的坐标是否一直
let headX=this.snakeBody[0].x*this.width;
let headY=this.snakeBody[0].y*this.height;
console.log(food.x+"======="+food.width);
console.log(food.y+"======="+food.height);
if(headX == food.x && headY == food.y){
//代表吃到食物了
//此时将蛇尾复制一份给蛇body,然后重新初始化食物
let lastBd=this.snakeBody[this.snakeBody.length-1];
this.snakeBody.push({
x:lastBd.x,
y:lastBd.y,
color:lastBd.color
})
food.init(map);
}
}
//小蛇元素删除方法
function remove() {
let i=elements.length-1;
//从身体最末尾开始删除
for(;i>=0;i--){
let ele=elements[i];
ele.parentElement.removeChild(ele);
elements.splice(i,1)
}
}
//把snake构造函数暴露给window
window.Snake=Snake;
}());
//游戏的自调用函数
(function () {
//创建构造函数
let _this=null;
function Game(map) {
this.food=new Food();
this.snake=new Snake();
this.map=map;
_this=this;
}
Game.prototype.init=function () {
this.food.init(this.map);
this.snake.init(this.map);
//在这里调用run方法实现小蛇自动跑
this.run();
//调用绑定键盘事件
this.bindKey();
// setInterval(function () {
// _this.snake.move();
// _this.snake.init(_this.map);
// },150)
};
Game.prototype.run=function () {
let timerId=setInterval(function () {
//调用bind 把that赋值给当前的this
this.snake.move(this.food,this.map);
this.snake.init(this.map);
let maxX=this.map.offsetWidth/this.snake.width;
let maxY=this.map.offsetHeight/this.snake.height;
let snakeObj=this.snake.snakeBody[0];
if(snakeObj.x<0 || snakeObj.x>=maxX){
alert("you are lose");
clearInterval(timerId);
}
if(snakeObj.y<0 || snakeObj.y>=maxY){
alert("you are lose");
clearInterval(timerId);
}
}.bind(_this),150)
};
Game.prototype.bindKey=function () {
// 绑定键盘事件
document.addEventListener("keydown",function (e) {
switch(e.keyCode){
case 37 :
this.snake.direction="left";
break;
case 38 :
this.snake.direction="top";
break;
case 39 :
this.snake.direction="right";
break;
case 40 :
this.snake.direction="bottom";
break;
}
}.bind(_this),false)
}
window.Game=Game;
}())
let gm=new Game(document.querySelector(".map"));
gm.init();
//如下所写不如再封装一个游戏的对象,在游戏对象中调用food和snake,这样代码更加简炼如上
//调用Food构造函数
// let fd=new Food();
// fd.init(document.querySelector(".map"));
// // fd.init(document.querySelector(".map"));
// //初始化snake
// let snake=new Snake();
// snake.init(document.querySelector(".map"));
// // snake.move();
// // snake.init(document.querySelector(".map"));
// // snake.move();
// // snake.init(document.querySelector(".map"));
// // snake.move();
// // snake.init(document.querySelector(".map"));
// setInterval(function () {
// snake.move();
// snake.init(document.querySelector(".map"));
// },150)
//测试一下这个fd有没有正常实例化
// console.log(fd.width+"====="+fd.x);//ok
</script>
</body>
</html>
前端基础学习之js-贪吃蛇游戏(面向对象思维)
最新推荐文章于 2022-07-11 22:13:30 发布