• 项目只有四个文件:index.html、Game.js、Snake.js、Food.js
  • 贪吃蛇游戏较为简单,有什么疑问欢迎在评论区探讨


  • index.html 文件
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body{
            background: rgb(0, 255, 221);
            color: #fff;
            text-align: center;
        }
        table{
            border-collapse: collapse;
            background:rgb(0, 255, 221);
            border:1px solid #fff;
            margin:50px auto;
        }
        td{
            width: 24px;
            height: 24px;
            color: blue;
            text-align: center;
            background: #333;
            border:1px solid #fff;
            border-radius: 50%;
        }
    </style>
</head>

<body>
    <h3 id = "f">帧编号:0</h3>
    <h3 id = "score">分数:0</h3>
    <div id="app"></div>
    <script src="js/Game.js"></script>
    <script src="js/Snake.js"></script>
    <script src="js/Food.js"></script>
    <script>
        var game = new Game();
    </script>

</body>

</html>
  • Game.js 文件
function Game(){
    //行数
    this.row = 20;
    //列数
    this.col = 20;
    //分数
    this.score = 0;
    //初始化节点
    this.init();
    //实例化蛇类
    this.snake = new Snake();
    //初始化食物
    this.food = new Food(this);
    //执行定时器任务
    this.start();
    //键盘的事件监听
    this.bindEvent();
    //
}
Game.prototype.init = function(){
    this.dom = document.createElement("table");
    var tr,td;
    // 遍历行与列上树
    for(var i = 0;i < this.row;i ++){
        //遍历行,创建节点上树
        tr = document.createElement("tr");

        //追加节点上树
        this.dom.appendChild(tr);

        for(var j = 0;j < this.col;j ++){
            //遍历列,创建节点上树
            td = document.createElement("td");

            //追加节点上树
            tr.appendChild(td);
        }
    }

    //表格上树
    document.getElementById("app").appendChild(this.dom); 
};

Game.prototype.clear = function(){
    //遍历表格,擦除画布
    for(var i = 0;i < this.row;i ++){
        for(var j = 0;j < this.col;j ++){
            this.dom.getElementsByTagName("tr")[i].getElementsByTagName("td")[j].style.backgroundColor = "rgb(0, 255, 221)";
            //删除食物
            this.dom.getElementsByTagName("tr")[i].getElementsByTagName("td")[j].innerHTML = "";
        }
    }
};

//设置颜色的方法
Game.prototype.setColor = function(row,col,color){
    //让表格的第几行第几列设置什么颜色
    this.dom.getElementsByTagName("tr")[row].getElementsByTagName("td")[col].style.backgroundColor = color;
};

//渲染食物
Game.prototype.setHTML = function(row,col,html){
    this.dom.getElementsByTagName("tr")[row].getElementsByTagName("td")[col].innerHTML = html;
};


//设置键盘的事件监听
Game.prototype.bindEvent = function(){
    var self = this;
    //键盘事件
    document.onkeydown = function(event){
        switch(event.keyCode){
            //按下左键
            case 37:
                //先进行判断,如果当前的方向向右移动,此时我们不能按左键
                if(game.snake.direction == "R"){
                    return;
                }
                // self.snake.direction = "L";
                self.snake.changeDirection("L");
                break;
            //按下上键
            case 38:
                //先进行判断,如果当前的方向向下移动,此时我们不能按上键
                if(game.snake.direction == "D"){
                    return;
                }
                // self.snake.direction = "U";
                self.snake.changeDirection("U");
                break;
            //按下右键
            case 39:
                if(game.snake.direction == "L"){
                    return;
                }
                // self.snake.direction = "R";
                self.snake.changeDirection("R");
                break;
            //按下下键
            case 40:
                if(game.snake.direction == "U"){
                    return;
                }
                // self.snake.direction = "D";
                self.snake.changeDirection("D");
                break;
        }
    };

};

Game.prototype.start = function(){
    //帧编号
    this.f = 0;
    this.timer = setInterval(function(){

        //定时器里面的核心就是游戏的渲染本质,清屏-更新-渲染
        game.f++;
        document.getElementById("f").innerHTML = "帧编号:" + game.f;

        //渲染分数
        document.getElementById("score").innerHTML = "分数:" + game.score;
        //清除屏幕
        game.clear();
    
        //蛇的更新
        //蛇的更新速度,当蛇变长的时候,速度要加快
        var during = game.snake.body.length < 30 ? 30 - game.snake.body.length : 1;
        game.f % during == 0 && game.snake.update();
    
        //蛇的渲染
        game.snake.render();

        //食物渲染
        game.food.render();
    
    },20);
    
};
  • Snake.js 文件
function Snake(){

    //蛇的初始化身体
    this.body = [
        {"row":3,"col":6},
        {"row":3,"col":5},
        {"row":3,"col":4},
        {"row":3,"col":3},
        {"row":3,"col":2}
    ];
    //信号量,蛇的运动方向
    this.direction = "R";
    //即将改变的方向,目的就是防止出现原地调头的情况
    this.willDirection = "R";
}

//蛇的运动
Snake.prototype.update = function(){
    //让当前的 direction 接收一下 willDirection 
    this.direction = this.willDirection;
    //蛇的不同方向的运动
    switch(this.direction){
        case "R":
            this.body.unshift({"row":this.body[0].row,"col":this.body[0].col + 1});
            break;
        case "D":
            this.body.unshift({"row":this.body[0].row + 1,"col":this.body[0].col});
            break;
        case "L":
            this.body.unshift({"row":this.body[0].row,"col":this.body[0].col - 1});
            break;
        case "U":
            this.body.unshift({"row":this.body[0].row - 1,"col":this.body[0].col});
            break;
    }

    //死亡的判定,超出了表格边缘的部分
    if(this.body[0].col > game.col - 1 || this.body[0].row > game.row - 1 || this.body[0].col < 0 || this.body[0].row < 0){
        
        //删除是因为当前的头增是不合法的
        this.body.shift();
        alert("游戏结束,您当前的得分为:" + game.score + "分");
        clearInterval(game.timer);
    }

    //死亡的判定,自己撞到了自己
    for(var i = 1;i < this.body.length; i ++){
        if(this.body[0].col == this.body[i].col && this.body[0].row == this.body[i].row){
            this.body.shift();
            alert("游戏结束,您当前的得分为:" + game.score + "分");
            clearInterval(game.timer);
        }
    }

    //蛇吃食物变长
    if(this.body[0].row == game.food.row && this.body[0].col == game.food.col){
        //删除原来的食物,还可以在 Game 中的 clear 方法中操作
        // game.setHTML(game.food.row,game.food.col,"");
        //创建新的食物
        game.food = new Food(game);
        //让帧编号归0,因为蛇会窜一下
        game.f = 0;
        //加分数
        game.score ++;
    }else{
        this.body.pop();
    }
};

//蛇的方向改变,防止的是一次渲染之前会出现调头的情况
Snake.prototype.changeDirection = function(d){
    this.willDirection = d;
};

Snake.prototype.render = function(){
    //蛇头的渲染
    game.setColor(this.body[0].row,this.body[0].col,'pink');
    //蛇身的渲染
    for(var i = 1;i < this.body.length;i ++){
        game.setColor(this.body[i].row,this.body[i].col,'cyan');
    }
};
  • Food.js 文件
function Food(gameSnake){
    var self = this;
    //食物的位置
    //先产生食物,在判断是否在蛇身上
    do{
        this.row = parseInt(Math.random() * gameSnake.row);
        this.col = parseInt(Math.random() * gameSnake.col);
    }while((function(){
        for(var i = 0 ;i < gameSnake.snake.body.length;i ++){
            if(gameSnake.snake.body[i].row == self.row && gameSnake.snake.body[i].col == self.col){
                return true;
            }
        }
        return false;
    })());
}

Food.prototype.render = function(){
    game.setHTML(this.row,this.col,"★");
}