js面向对象简易贪吃蛇
1.贪吃蛇.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.container {
width: 600px;
height: 600px;
border: 1px solid #ccc;
margin: 0 auto;
}
</style>
</head>
<body>
//创建一个贪吃蛇活动的范围
<div class="container"></div>
//引入各个js文件
<script src="js/Game.js"></script>
<script src="js/Map.js"></script>
<script src="js/Snake.js"></script>
<script src="js/Food.js"></script>
<script>
//获得贪吃蛇活动的范围
var container = document.querySelector('.container');
//创建map实例对象 传入地图的宽高 行列数
var map = new Map(container.clientWidth, container.clientHeight, 20, 20);
//创建蛇实例对象
var snake = new Snake();
//创建食物实例对象
var food = new Food(7, 5);
//创建游戏实例对象 传入贪吃蛇活动的范围 以及地图 蛇 食物三个实例对象
var g = new Game(container, map, snake, food);
</script>
</body>
</html>
2.map.js
function Map(width, height, row, col) {
//获取容器的宽高 行数 列数
this.width = width;
this.height = height;
this.row = row;
this.col = col;
//创建地图
this.div = document.createElement('div');
//二维数组接收行和列
this.arr = [];
//行数组接收行
this.rowArr = [];
//初始化行数
this.init();
}
Map.prototype.init = function() {
this.fill();
this.addStyle();
}
//构建架构的函数
Map.prototype.fill = function() {
//循环行数创建行
for (var i = 0; i < this.row; i++) {
var rowElement = document.createElement("div");
rowElement.className = "row";
//将创建出来的行添加到存放行的数组中
this.rowArr.push(rowElement);
//创建一个空数组存放列
var colArr = [];
//循环列数 创建列
for (var j = 0; j < this.col; j++) {
var colElement = document.createElement("div");
colElement.className = "col";
//将创建出来的列添加到数组中
colArr.push(colElement)
//将列添加到行中
rowElement.appendChild(colElement);
}
//将存放列的数组添加到数组中 最终生成一个二维数组
this.arr.push(colArr);
//地图添加每一行
this.div.appendChild(rowElement);
}
// console.log(this.arr);
// console.log(this.rowArr);
}
//渲染样式
Map.prototype.addStyle = function() {
//地图占据容器百分之百
var divStyle = {
width: '100%',
height: '100%'
}
for (var i in divStyle) {
this.div.style[i] = divStyle[i];
}
//每一行的样式
var rowStyle = {
width: '100%',
height: 100 / this.row + '%',
borderBottom: '1px solid #ccc',
boxSizing: 'border-box'
}
for (var i in rowStyle) {
this.rowArr.forEach(item => {
item.style[i] = rowStyle[i];
})
}
//最后一行不需要下边框
var rowArrLength = this.rowArr.length - 1;
this.rowArr[rowArrLength].style.borderBottom = 'none';
//每一列的样式
var colStyle = {
width: 100 / this.col + '%',
height: '100%',
borderRight: '1px solid #ccc',
boxSizing: 'border-box',
float: 'left'
}
//遍历二维数组
this.arr.forEach(item => {
item.forEach(value => {
for (var i in colStyle) {
value.style[i] = colStyle[i]
}
})
//最后一列不需要右边框
var colLength = item.length - 1;
item[colLength].style.borderRight = 'none'
})
}
//清除整个地图中蛇占据的位置
Map.prototype.clear = function() {
this.arr.forEach(item => {
item.forEach(value => {
value.style.backgroundColor = 'white'
})
})
}
3.game.js
function Game(container, map, snake, food) {
//获取存放地图的容器 已经地图对象 蛇对象 食物对象
this.container = container;
this.map = map;
this.snake = snake;
this.food = food;
//初始化函数
this.init();
//游戏开始与结束的标志位
this.flag = true;
}
Game.prototype = {
constructor: Game,
init() {
this.renderMap();
this.renderSnake();
this.startMove();
this.changeDirection();
},
//渲染地图
renderMap() {
//将map实例创建出来的地图渲染到存放地图的容器中
this.container.appendChild(this.map.div);
},
//渲染食物
renderFood() {
let { x, y } = this.food;
this.map.arr[x][y].style.backgroundColor = "pink";
},
//渲染蛇
renderSnake() {
this.snake.arr.forEach(({ x, y }) => {
this.map.arr[x][y].style.backgroundColor = "red"
})
},
//蛇运动的函数
startMove() {
//定义定时器让蛇一直运动
this.timer = setInterval(() => {
//改变蛇的位置的数组
this.snake.move();
//当蛇运动的时候 也不断地检测是否触发事件
this.check();
//当游戏是否开启的标志位为false时 游戏结束
if (!this.flag) {
return;
}
//清除地图上蛇的样式 再重新渲染蛇
this.map.clear();
//渲染蛇
this.renderSnake();
//渲染食物
this.renderFood();
}, 500)
},
//按键事件
changeDirection() {
//将相应的按键码传递给snake中改变蛇方向的函数
document.addEventListener('keypress', (e) => {
// console.log(e.key);
switch (e.key) {
case "w":
case "a":
case 's':
case "d":
this.snake.switchDirection(e.key);
break;
}
});
},
//检测事件
check() {
//当蛇撞到墙的时候
this.touchWall();
//当蛇吃到食物的时候
this.eat();
//当蛇自己吃自己的时候
this.eatSelf();
},
//撞墙事件
touchWall() {
//得到当前蛇头的位置
let { x, y } = this.snake.arr.slice(-1)[0];
//当蛇头的位置小于或大于当前行数列数的时候 就游戏结束时
if (x < 0 || y < 0 || x >= this.map.row || y >= this.map.col) {
this.gameOver();
}
},
//游戏结束事件
gameOver() {
//将游戏是否开启的标志位置为false
this.flag = false;
},
//吃到食物的事件
eat() {
//得到当前蛇头的位置
let snakeHeadX = this.snake.arr.slice(-1)[0].x;
let snakeHeadY = this.snake.arr.slice(-1)[0].y;
//得到当前食物的位置
let { x, y } = this.food;
//当蛇头的位置和食物的位置相同时 代表着吃到了食物
if (x === snakeHeadX && y === snakeHeadY) {
//让蛇长大
this.snake.growUp();
//重新渲染食物
this.resetFood();
}
},
//重新渲染食物
resetFood() {
//重新给一个食物的位置
let x = parseInt(Math.random() * this.map.row);
let y = parseInt(Math.random() * this.map.col);
//判断重新生成的食物的位置是不是与当前蛇的位置重合
let isExist = this.snake.arr.some(value => {
return value.x === x && value.y === y;
});
//重合的话 再重新渲染食物
if (isExist) {
this.resetFood();
return;
}
//将重新得到的位置给到食物
this.food.x = x;
this.food.y = y;
},
//吃自己的事件
eatSelf() {
//得到当前蛇的头部的位置
let { x, y } = this.snake.arr.slice(-1)[0];
//得到当前除了蛇头蛇其他部位的位置
let otherArr = this.snake.arr.slice(0, -1);
//判断蛇头的位置是否与蛇身的位置重合
let isExist = otherArr.some((item) => {
return x === item.x && y === item.y
});
//重合的话 游戏结束
if (isExist) {
this.gameOver();
}
}
}
4.food.js
function Food(x, y) {
//x y是食物的位置
this.x = x;
this.y = y;
}
5.snake.js
function Snake() {
//arr是蛇的位置
this.arr = [{ x: 3, y: 3 }, { x: 3, y: 4 }, { x: 3, y: 5 }, { x: 3, y: 6 }];
//蛇的方向
this.direction = "R";
//蛇是否转向完成的标志位
this.flag = true;
}
//move的本质是重新给this.arr数组赋值
Snake.prototype.move = function() {
//删除数组的第一位
this.arr.shift();
let newHead = {
...this.arr[this.arr.length - 1],
}
//根据当前方向 决定添加头部的位置
if (this.direction === "R") {
newHead.y++;
} else if (this.direction === "L") {
// 如果方向是向左 y - 1
newHead.y--;
} else if (this.direction === "U") {
// 如果方向是向上 x - 1;
newHead.x--;
} else if (this.direction === "D") {
// 如果方向是向下 x + 1
newHead.x++
}
//添加数组的第一位
this.arr.push(newHead);
//将可以转向变为true
this.flag = true;
}
Snake.prototype.switchDirection = function(keyChar) {
//当转向还没有完成的时候
if (!this.flag) {
return;
}
//当键盘按下对应的按键且当前的方向不为反方向的话 若为反方向就会自己吃自己
if (keyChar == 'w' && this.direction != 'D') {
this.direction = 'U';
} else if (keyChar == 'a' && this.direction != 'R') {
this.direction = "L";
} else if (keyChar == 's' && this.direction != 'U') {
this.direction = "D";
} else if (keyChar == 'd' && this.direction != 'L') {
this.direction = "R"
}
//将可否转向的标志位置为false
this.flag = false;
};
//蛇长大的事件
Snake.prototype.growUp = function() {
//得到蛇尾部的位置
let newTail = {
...this.arr[0]
}
console.log(newTail);
//将蛇尾部的位置 添加到数组中
this.arr.unshift(newTail);
}