js实现简单的贪吃蛇游戏

  主要就是运用面向对象的思想来解决贪吃蛇的游戏。思路也不是很难,创建三个对象,食物,蛇还有游戏(用于游戏的初始化控制等)。采用改进的工厂模式创建对象,再利用原型创建公共方法。

1.食物有坐标(x,y),宽,高还有颜色五个属性。有初始化的方法(随机出现在地图上)。用自调用函数封装,然后把构造函数赋给windows,使得可以全局调用创建对象

//自调用函数food
(function () {
    var elements = [];//用于保存食物元素
    //食物对象,包含宽,高,颜色,横纵坐标属性
    function Food(x, y, width, height, color) {
        this.x = x || 0;
        this.y = y || 0;
        this.width = width || 20;
        this.heigth = height || 20;
        this.color = color || "green";
    }

    //为食物对象添加初始化方法(作用,随机出现在地图上)
    Food.prototype.init = function (map) {
        //remove the food first
        remove();
        //create div
        var div = document.createElement("div");
        //add div to map
        map.appendChild(div);
        //assign value to div
        div.style.width = this.width + "px";//do not forget px!!!
        div.style.height = this.heigth + "px";
        div.style.backgroundColor = this.color;
        //position is random
        div.style.position = "absolute";
        this.x = parseInt(Math.random() * (map.offsetWidth / this.width)) * this.width;
        this.y = parseInt(Math.random() * (map.offsetHeight / this.heigth)) * this.width;
        div.style.left = this.x + "px";
        div.style.top = this.y + "px";
        //add div to the elements
        elements.push(div);
    }

    //private function to delete food
    function remove() {
        for (var i = 0; i < elements.length; i++) {
            var ele = elements[i];
            ele.parentNode.removeChild(ele);
            elements.splice(i, 1);
        }
    }

    window.Food = Food;
}());

2.蛇。蛇有宽,高,坐标还有颜色五个属性,因为蛇的长度会变,所以可以将蛇又拆分成多个对象,根据实际长改变其对象个数。宽高都是一样的,就坐标和颜色不同。用一个数组来储存这些对象,以便后面的修改。蛇有初始化的方法,创建标签元素显示在地图上,同时还有移动的方法,处理蛇的每次移动。

//snake
(function () {
    //create an array to store snake
    var elements = [];

    //constructor for snake
    function Snake(width, height, direction) {
        //the width and height of every part of snake,all the same
        this.width = width || 20;
        this.height = height || 20;
        //the body of snake
        this.body = [
            {x: 3, y: 2, color: "red"},//head
            {x: 2, y: 2, color: "orange"},//body
            {x: 1, y: 2, color: "orange"}//body
        ];
        //direction
        this.direction = direction || "right";
    }

    //create init function
    Snake.prototype.init = function (map) {
        //delete the snake before
        remove();
        // traverse the array to create div
        for (let i = 0; i < this.body.length; i++) {
            let obj = this.body[i];
            //create div
            let div = document.createElement("div");
            //append div to map
            map.appendChild(div);
            //set style for div
            div.style.position = "absolute";
            div.style.width = this.width + "px";
            div.style.height = this.height + "px";
            div.style.left = obj.x * this.width + "px";
            div.style.top = obj.y * this.height + "px";
            div.style.backgroundColor = obj.color;

            //add div to array to delete more convenient later
            elements.push(div);
        }
    }
    //move the snake
    Snake.prototype.move = function (food, map) {
        //change the position of body
        var i = this.body.length - 1;
        for (; i > 0; i--) {//make sure the later followed the head!
            this.body[i].x = this.body[i - 1].x;
            this.body[i].y = this.body[i - 1].y;
        }
        //change the position of head
        switch (this.direction) {
            case "right":
                this.body[0].x++;
                break;
            case "left":
                this.body[0].x--;
                break;
            case "top":
                this.body[0].y--;
                break;
            case "bottom":
                this.body[0].y++;
                break;
        }
        //judge if the food was ate
        //position of head of snake
        var headX = this.body[0].x*this.width;
        var headY = this.body[0].y*this.height;
        //position of food
        var foodX = food.x;
        var foodY = food.y;
        //judge
        // console.log(this.body);

        if (headX==foodX&&headY==foodY){
            //the length of snake +1
            var last = this.body[this.body.length-1];//刚开始加上的方块和原先的最后一块方块是重叠,但在下一次移动的时候加上的方块
            //位置不变,因为会移到前面一块方块地方,而原先的尾巴就移走了,此时就没有重叠了,soga
            this.body.push({
                x:last.x,
                y:last.y,
                color:last.color
            });
            //delete food and generate new food
            food.init(map);
        }
    }

    //delete snake function
    function remove() {
        //by array
        for (var i = elements.length - 1; i >= 0; i--) {
            // delete
            elements[i].parentNode.removeChild(elements[i]);
            //delete from array,too
            elements.splice(i, 1);
        }
    }

    window.Snake = Snake;
}());

3.游戏对象,主要有食物还有蛇对象的创建,还有游戏的初始化,让蛇跑起来。同时包含键盘事件,用于控制蛇的移动,还有鼠标事件用于控制游戏的难度,暂停继续等。

//game
(function () {
    var that = null;
    var speed = 200;
    //create constructor of game
    function Game(map) {
        this.food = new Food();
        this.snake = new Snake();
        this.map = map;
        this.timeId = null;
        that = this;//use for setInterval
    }

    Game.prototype.init = function () {
        //init food
        this.food.init(this.map);
        //init snake
        this.snake.init(this.map);
        //play the game
        this.run(this.food, this.map);
        //change direction
        this.bindKey();
        this.bindMouse();
        // setInterval(function () {
        //     this.snake.move()
        // })this is window ,so cannot use it
        // setInterval(function () {
        //     that.snake.move(that.food,that.map);
        //     that.snake.init(that.map);
        // },150);//do not use setInterval here
    }
    //snake running
    Game.prototype.run = function (food, map) {
        if (this.timeId){
            clearInterval(this.timeId);
        }
        this.timeId = setInterval(function () {
            var snake = this.snake;
            //move the snake
            snake.move(food, map);
            //init snake
            snake.init(map);
            //the max x and y
            var maxX = map.offsetWidth / snake.width;
            var maxY = map.offsetHeight / snake.height;
            //the position of snake
            var headX = snake.body[0].x;
            var headY = snake.body[0].y;
            //judge
            if (headX < 0 || headX >= maxX) {
                clearInterval(this.timeId);
                alert("game over");
            }
            if (headY < 0 || headY >= maxY) {
                clearInterval(this.timeId);
                alert("game over");
            }
            for (let i = 1;i <snake.body.length;i++){
                if (headX==snake.body[i].x&&headY==snake.body[i].y){
                    clearInterval(this.timeId);
                    alert("game over");
                }
            }
        }.bind(that), speed)//use bind to bind Game object
    }
    //get the key to change the direction
    Game.prototype.bindKey = function(){
        //get the key user press and change the direction
        document.addEventListener("keydown",function (e) {
            //this is document ,so use bind function
            // 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;
            // }
            //when left or right,cannot press left or right,only top or bottom,yeah
            if (this.snake.direction=="left"||this.snake.direction=="right") {
                switch (e.keyCode) {
                    case 38:this.snake.direction = "top";break;
                    case 40:this.snake.direction = "bottom";break;
                }
            }else{
                switch (e.keyCode) {
                    case 37:this.snake.direction = "left";break;
                    case 39:this.snake.direction = "right";break;
                }
            }
        }.bind(that),false)

    }
    //bind mouse click event
    Game.prototype.bindMouse = function(){
        var btn = document.getElementById("btn").getElementsByTagName("button");
        for (let i = 0;i < btn.length-2;i++){
            btn[i].onclick = function () {
                speed=250-50*i;
                if (i==4){
                    speed = 20;
                }
                this.run(this.food, this.map);
            }.bind(that);
        }
        //pause
        btn[5].onclick = function () {
            clearInterval(this.timeId);
        }.bind(that);
        //continue
        btn[6].onclick = function () {
            this.run(this.food, this.map);
        }.bind(that);

    }
    window.Game = Game;
}());

将以上三个放在三个js文件中,如下是html内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>贪吃蛇</title>
    <style>
        .map {
            width: 800px;
            height: 580px;
            background-color: #CCCCCC;
            position: relative;
        }
        button{
            width: 80px;
            height: 30px;
            background-color: #0000ff;
            color: #ff0000;
            position: absolute;
            font-size: 14px;
        }
        /*choose the first child of the father of button*/
        button:nth-child(1){
            top: 50px;
            left: 860px;
        }
        button:nth-child(2){
            top: 100px;
            left: 860px;
        }
        button:nth-child(3){
            top: 150px;
            left: 860px;
        }
        button:nth-child(4){
            top: 200px;
            left: 860px;
        }
        button:nth-child(5){
            top: 250px;
            left: 860px;
        }
        button:nth-child(6){
            top: 300px;
            left: 860px;
        }
        button:nth-child(7){
            top: 350px;
            left: 860px;
        }
    </style>
</head>
<body>
<!--画出地图,设置样式-->
<div class="map"></div>
<div id="btn">
<button id="easy">easy</button>
<button id="normal">normal</button>
<button id="hard">hard</button>
<button id="veryHard">very hard</button>
<button id="crazy">crazy</button>
<button id="pause">pause</button>
<button id="continue">continue</button>
</div>
<script src="food.js"></script>
<script src="snake.js"></script>
<script src="game.js"></script>
<script>
    //test the game
    var map = document.querySelector(".map");
    var game = new Game(map);
    game.init();
    // //外部测试代码
    // var fd = new Food();
    // fd.init(map);
    // var sk = new Snake();
    // sk.init(map);//generate snake
    // sk.move(fd,map);//move snake
    // sk.init(map);//delete former snake and generate new snake
</script>
</body>
</html>

至此,一个简单的贪吃蛇游戏就完成了,后面的重来,计分等功能可以自己添加。效果如下:

js实现简单的贪吃蛇游戏