console
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>贪吃蛇</title>
</head>
<body>
<script type="text/javascript">
// ES5的语法中 js没有块级作用域的概念
// 用自执行函数充当块级作用域
/* 地图类*/
(function() {
// 地图构造函数 需要三个参数 宽高背景色
function Map(width,height,bgColor){
this.width = width;
this.height = height;
this.bgColor = bgColor;
}
// 将公共方法创建到原型对象上
Map.prototype.init = function(){
// 创建一个div
let divMap = document.createElement('div')
// 设置宽高背景色
divMap.style.width = this.width + 'px';
divMap.style.height = this.height + 'px';
divMap.style.backgroundColor = this.bgColor
divMap.style.left = '50%'
divMap.style.transform = 'translate(-50%,15%)'
// 设置divMap 相对定位(作为食物的包含块)
divMap.style.position = 'relative'
divMap.id = 'divMap'
// 添加到body中
document.body.append(divMap)
}
// 将构造函数Map挂载到window上 暴露出去
window.Map = Map
})();
// 食物类
(function() {
// 食物数组
let elements = [];
// 食物构造函数
function Food(width,height,bgColor){
this.width = width;
this.height = height;
this.bgColor = bgColor;
this.x = 0;
this.y = 0;
}
// 食物原型
Food.prototype.init = function(){
// 先删除
remove();
// 创建食物
let divFood = document.createElement('div')
// 获取divMap
let divMap = document.getElementById('divMap')
// 设置食物div的css属性
divFood.style.width = this.width + 'px'
divFood.style.height = this.height + 'px'
divFood.style.backgroundColor = this.bgColor
divFood.style.position = 'absolute'
/*
x和y存储的是格数, 用地图的宽度800除以食物的宽度20等于40, 生成一个0-40之间的随机数
再向下取整 就得到了食物X轴和Y轴的格数 再乘以自身的宽高就得到了食物的left和top值
*/
this.x = Math.floor(Math.random() * (divMap.offsetWidth / this.width))
this.y = Math.floor(Math.random() * (divMap.offsetHeight / this.height))
divFood.style.left = this.x * this.width + 'px'
divFood.style.top = this.y * this.height + 'px'
// 添加到divMap中
divMap.appendChild(divFood)
// 将divFood存到食物数组中
elements.push(divFood)
}
function remove() {
let divMap = document.getElementById('divMap')
for (let i = 0; i < elements.length; i++) {
// 删除divMap中的食物
divMap.removeChild(elements[i])
// 清空食物数组
elements.splice(i, 1)
}
}
// 将构造函数Food挂载到window上
window.Food = Food
})();
// 蛇类
(function() {
// 蛇数组
let elements = []
// 蛇构造函数 dir表示方向
function Snake(width,height,dir) {
this.width = width
this.height = height
this.dir = dir
// this.snBody表示整条蛇, 以数组的形式存储三个对象 分别代蛇头 蛇身 蛇尾
this.snBody = [{
x:3,
y:2,
bgColor: 'red'
},{
x:2,
y:2,
bgColor: '#64f'
},{
x:1,
y:2,
bgColor: '#64f'
}]
}
// 初始化蛇
Snake.prototype.init = function(){
// 干掉死去的蛇
remove();
// 分别创建蛇头 蛇中 蛇尾3个div 分别设置div的css属性
let divMap = document.getElementById('divMap')
for(let i = 0; i < this.snBody.length; i++) {
let divSnake = document.createElement('div')
divSnake.style.width = this.width + 'px'
divSnake.style.height = this.height + 'px'
divSnake.style.background = this.snBody[i].bgColor;
divSnake.style.position = 'absolute'
divSnake.style.left = this.snBody[i].x * this.width + 'px'
divSnake.style.top = this.snBody[i].y * this.height + 'px'
// 添加到dom上
divMap.appendChild(divSnake)
elements.push(divSnake)
}
}
// 蛇移动
Snake.prototype.move = function(){
// 把蛇中的xy给蛇尾 把蛇头的xy给蛇中
for(let i = this.snBody.length - 1; i > 0; i--){
this.snBody[i].x = this.snBody[i - 1].x
this.snBody[i].y = this.snBody[i - 1].y
}
// 根据dir的值来决定蛇头的方向
if(this.dir === 'right') {
// 蛇头x自加1
this.snBody[0].x += 1
}
if(this.dir === 'left') {
// 蛇头x自减1
this.snBody[0].x -= 1
}
if(this.dir === 'top') {
// 蛇头x自减1
this.snBody[0].y -= 1
}
if(this.dir === 'bottom') {
// 蛇头x自加1
this.snBody[0].y += 1
}
}
// 删除方法
function remove() {
// 获取地图div
let divMap = document.getElementById('divMap')
// 反向遍历 从蛇尾往蛇头删除
for(let i = elements.length - 1; i >= 0; i--) {
// 删除地图div中的dom
divMap.removeChild(elements[i])
// 删除蛇数组中的元素
elements.splice(i, 1)
}
}
window.Snake = Snake
})();
// 游戏类 定义游戏规则
(function(){
// 用来存储game实例对象
let gameThis = null
let timer = 0
// 游戏构造函数
function Game() {
// 实例化地图对象
this.mapG = new Map(800, 600, '#ccc')
// 实例化食物对象
this.food = new Food(20, 20, 'green')
// 实例化蛇对象
this.snake = new Snake(20, 20, 'right')
}
Game.prototype.init = function(){
// 用对象调原型对象中的init方法
this.mapG.init()
this.food.init()
this.snake.init()
}
// 游戏规则
Game.prototype.ruler = function(){
// 将game实例对象保存到局部变量中
gameThis = this
// 所有的游戏规则都要在定时器内
timer = setInterval(function(){
// 调用蛇移动函数
gameThis.snake.move()
// 调用蛇初始化函数
gameThis.snake.init()
// 判断蛇是否超出边界(四个方向)
if(gameThis.snake.snBody[0].x < 0 || (gameThis.snake.snBody[0].x >= gameThis.mapG.width / gameThis.snake.width) || gameThis.snake.snBody[0].y < 0 || (gameThis.snake.snBody[0].y >= gameThis.mapG.height / gameThis.snake.height)) {
console.log('Game Over')
// 关闭定时器
clearInterval(timer)
// 弹出对话框
let divOver = document.createElement('div')
divOver.style.width = '300px'
divOver.style.height = '200px'
divOver.style.background = 'rgba(255,0,0,0.7)'
divOver.style.lineHeight = '200px'
divOver.style.textAlign = 'center'
divOver.style.position = 'absolute'
divOver.style.left = '50%'
divOver.style.marginLeft = '-150px'
divOver.style.top = '50%'
divOver.style.marginTop = '-100px'
divOver.style.zIndex = '10'
document.body.appendChild(divOver)
let btnAgain = document.createElement('button')
btnAgain.innerText = 'try angin'
btnAgain.style.cursor = 'pointer'
btnAgain.onclick = function() {
// 刷新
window.location.reload()
}
divOver.appendChild(btnAgain)
}
// 吃食物长尾巴 删除食物 重新生成新食物
if(gameThis.snake.snBody[0].x === gameThis.food.x && gameThis.snake.snBody[0].y === gameThis.food.y) {
console.log('吃到了')
gameThis.food.init()
// 创建新增蛇尾的对象 把最后一节蛇尾的x和y 赋值给新增的
let t = {
x: gameThis.snake.snBody[gameThis.snake.snBody.length - 1].x,
y: gameThis.snake.snBody[gameThis.snake.snBody.length - 1].y,
bgColor: '#64f'
}
// 将元素添加到数组中
gameThis.snake.snBody.push(t)
}
// 键盘按下事件
document.onkeydown = function(e){
if(e.keyCode === 37) {
// 向左
gameThis.snake.dir = 'left'
}
if(e.keyCode === 38) {
// 向上
gameThis.snake.dir = 'top'
}
if(e.keyCode === 39) {
// 向右
gameThis.snake.dir = 'right'
}
if(e.keyCode === 40) {
// 向下
gameThis.snake.dir = 'bottom'
}
}
},100)
}
window.Game = Game
})();
// 游戏实例对象
let game = new Game()
// 游戏初始化
game.init()
// 游戏规则方法
game.ruler()
</script>
</body>
</html>