typora-copy-images-to: media


贪吃蛇

从贪吃蛇的游戏中,不难看出,整个游戏分3个对象组成,分别是地图、食物、蛇

工具类函数:

// 设置样式的函数
function setStyle(ele,styleObj){
    for(var attr in styleObj){
        ele.style[attr] = styleObj[attr];
    }
}
// 随机数函数
function getRandom(a,b){
    var max = a;
    var min = b;
    if(a<b){
        max = b;
        min = a;
    }
    return Math.floor(Math.random()*(max-min))+min;
}

地图:

// 地图对象
function Map(){
    this.map = document.createElement("div");
    setStyle(this.map,{
        width:'800px',
        height:'500px',
        border:'10px solid #000',
        backgroundColor:'#ccc',
        position:'relative'
    });
    document.body.appendChild(this.map);
}
var map = new Map();

地图显示效果:

地图显示

食物:

// 食物对象
function Food(){
    this.food = document.createElement("div");
    var foodLeft = Math.floor(getRandom(0,map.map.clientWidth-10)/10)*10;
    var foodTop = Math.floor(getRandom(0,map.map.clientHeight-10)/10)*10;
    setStyle(this.food,{
        width:'10px',
        height:'10px',
        backgroundColor:'#0f0',
        position:'absolute',
        left:foodLeft + 'px',
        top:foodTop + 'px',
    });
    map.map.appendChild(this.food);
}
var food = new Food();

食物显示效果:

食物显示

蛇:

// 蛇
function Snake(){
    // 蛇的属性:身体、移动方向
    this.body = [
        {
            x:0,
            y:0,
        },
        {
            x:10,
            y:0
        },
        {
            x:20,
            y:0
        }
    ];
    this.direction = 'right';
    // 调用方法
    // 显示身体
    this.showBody();
    // 改变方向
    this.changeDirection();
}

蛇的方法:显示身体、改变方向、根据方向移动身体、吃食物、死亡

// 显示身体
Snake.prototype.showBody = function(){
    // 判断是否有蛇在显示,如果有就先删除再显示,如果没有就直接显示
    var snakes = document.querySelectorAll('.snake');
    if(snakes.length){
        for(var i=0;i<snakes.length;i++){
            map.map.removeChild(snakes[i]);
        }
    }
    for(var i=0;i<this.body.length;i++){
        var div = document.createElement("div");
        div.className = 'snake';
        setStyle(div,{
            width:'10px',
            height:'10px',
            background:'#00f',
            position:'absolute',
            left:this.body[i].x + 'px',
            top:this.body[i].y + 'px',
        });
        if(i==this.body.length-1){
            div.style.borderRadius = '50%';
            div.style.backgroundColor = '#f00';
        }
        map.map.appendChild(div);
    }   
}
// 改变移动方向
Snake.prototype.changeDirection = function(){
    window.onkeypress = e=>{
        var e = e || window.event;
        var keycode = e.keyCode || e.which;
        var key = String.fromCharCode(keycode);
        switch(key.toLowerCase()){
            case 'w':
                this.direction = 'up';
            break;
            case 's':
                this.direction = 'down';
            break;
            case 'a':
                this.direction = 'left';
            break;
            case 'd':
                this.direction = 'right';
        }
    }
}
// 根据方向移动身体
Snake.prototype.moveBody = function(){
    // 处理蛇的身体
    for(var i=0;i<this.body.length-1;i++){
        this.body[i].x = this.body[i+1].x
        this.body[i].y = this.body[i+1].y
    }
    // 根据方向设置蛇头
    switch(this.direction){
        case 'up':
            this.body[this.body.length-1].y -= 10
        break;
        case 'down':
            this.body[this.body.length-1].y += 10
        break;
        case 'left':
            this.body[this.body.length-1].x -= 10
        break;
        case 'right':
            this.body[this.body.length-1].x += 10
    }
    // 重新显示身体
    this.showBody()
    // 移动过程中吃食物
    this.eatFood()
    // 移动过程中可能死亡
    this.die()
}
// 吃食物
Snake.prototype.eatFood = function(){
    if(this.body[this.body.length-1].x === food.food.offsetLeft && this.body[this.body.length-1].y === food.food.offsetTop){
        map.map.removeChild(food.food);
        food = new Food();
        var newBody = Object.assign({},this.body[0]);
        this.body.unshift(newBody);
    }
}
// 死亡
Snake.prototype.die = function(){
    // 将蛇头定义起来
    var head = this.body[this.body.length-1];
    // 撞墙
    if(head.x<0 || head.y<0 || head.x>map.map.clientWidth-10 || head.y>map.map.clientHeight-10){
        alert("GAME OVER!!!");
        clearInterval(this.timerId)
    }
    // 撞身体
    for(var i=0;i<this.body.length-1;i++){
        if(head.x === this.body[i].x && head.y === this.body[i].y){
            alert("GAME OVER!!!");
            clearInterval(this.timerId)
        }
    }
}
// 初始化方法 - 开始游戏
Snake.prototype.init = function(){
    // 不停的根据方向移动身体
    this.timerId = setInterval(()=>{
        this.moveBody()
    },200);
}

调用:

var snake = new Snake();
snake.init()

游戏效果:

游戏效果

处理死亡后的超出:

修改移动方法

// 根据方向移动身体
Snake.prototype.moveBody = function(){
    // 在蛇的身体未移动之前,先将身体深克隆一份
    var oldBody = JSON.parse(JSON.stringify(this.body));
    // 处理蛇的身体
    for(var i=0;i<this.body.length-1;i++){
        this.body[i].x = this.body[i+1].x
        this.body[i].y = this.body[i+1].y
    }
    // 根据方向设置蛇头
    switch(this.direction){
        case 'up':
            this.body[this.body.length-1].y -= 10
        break;
        case 'down':
            this.body[this.body.length-1].y += 10
        break;
        case 'left':
            this.body[this.body.length-1].x -= 10
        break;
        case 'right':
            this.body[this.body.length-1].x += 10
    }
    // 移动过程中可能死亡 - 先判断死亡再显示新的身体
    this.die(oldBody) // 将死亡之前的身体传入死亡方法
    // 重新显示身体
    this.showBody()
    // 移动过程中吃食物
    this.eatFood()
}

修改死亡方法:

// 死亡
Snake.prototype.die = function(oldBody){ // 接收蛇死亡之前的身体
    // 将蛇头定义起来
    var head = this.body[this.body.length-1];
    // 撞墙
    if(head.x<0 || head.y<0 || head.x>map.map.clientWidth-10 || head.y>map.map.clientHeight-10){
        this.body = oldBody // 将蛇的身体退回到死亡之前
        alert("GAME OVER!!!");
        clearInterval(this.timerId)
    }
    // 撞身体
    for(var i=0;i<this.body.length-1;i++){
        if(head.x === this.body[i].x && head.y === this.body[i].y){
            this.body = oldBody // 将蛇的身体退回到死亡之前
            alert("GAME OVER!!!");
            clearInterval(this.timerId)
        }
    }
}