面向对象实现简易贪吃蛇

实现思路

1.创建一个包含宽度、高度、蛇移动方向、蛇组成(包含蛇头蛇尾)等属性以及包含绘制、移动等方法的蛇对象;

主要代码:

 function Snake(options) {
        options = options || {};
        // 1. 属性
        // 1.1 蛇节
        this.width = options.width || 20;
        this.height = options.height || 20;
        // 1.2 蛇移动的方向
        this.direction = options.direction || 'right';
        // 1.3 蛇的身体和蛇头
        this.body = [
            {x: 2, y: 0, color: 'purple'}, // 蛇头
            {x: 1, y: 0, color: 'red'}, // 蛇节
            {x: 0, y: 0, color: 'red'} // 蛇节
        ];
    }
     Snake.prototype = {
        constructor: Snake,
        // 绘制
        render: function (panel) {
            // 1. 删除旧蛇
            remove();
        },
        // 移动
        move: function (food, panel) {
           
        }
    }
};

2.创建一个包含(用x,y坐标定义)位置、宽度高度、颜色等属性以及包含绘制方法的食物对象;

 function Food(options) {
        options = options || {};
        // 1. 属性
        this.x = options.x || 0;
        this.y = options.y || 0;
        this.width = options.width || 20;
        this.height = options.height || 20;
        this.color = options.color || 'red';
    }
Food.prototype = {
        constructor: Food,
        // 绘制食物
        render: function (panel) {
            // 0. 绘制之前先删除
            remove();

            // 1. 随机位置
            this.x = _.random(0, panel.clientWidth/this.width - 1) * this.width;
            this.y = _.random(0, panel.clientHeight/this.height - 1) * this.height;
            // console.log(panel.clientWidth, this.width);

            // 2. 动态创建食物div
            var div = document.createElement('div');
            div.style.position = 'absolute';
            div.style.top = this.y + 'px';
            div.style.left = this.x + 'px';
            div.style.width = this.width + 'px';
            div.style.height = this.height + 'px';
            div.style.backgroundColor =  this.color;
            div.style.borderRadius =  this.width * 0.5 + 'px';
            panel.appendChild(div);
            foodArr.push(div);
        }
    };

3.在蛇的绘制方法中依照定义的蛇的属性去绘制小蛇(包含蛇头以及蛇尾位置,宽度高度,颜色等),注意:绘制前先要删除掉旧蛇。定义蛇的移动方法包含蛇头和蛇身,起到灵魂作用的是蛇头,用它控制了蛇的移动方向(上:蛇头y坐标-1,下:蛇头y坐标+1,左:蛇头x坐标-1,右:蛇头x坐标+1)蛇身(当前蛇节移动到上一个蛇节的位置即可)

    Snake.prototype = {
        constructor: Snake,
        // 绘制
        render: function (panel) {
            // 1. 删除旧蛇
            remove();

            // 2. 绘制新蛇
            for (var i = 0, len = this.body.length; i < len; i++) {
                // 1. 取出蛇的信息
                var obj = this.body[i];
                // 2. 创建蛇节和蛇头
                var div = document.createElement('div');
                div.style.position = 'absolute';
                div.style.left = obj.x * this.width + 'px';
                div.style.top = obj.y * this.height + 'px';
                div.style.width = this.width + 'px';
                div.style.height = this.height + 'px';
                div.style.backgroundColor = obj.color;
                div.style.borderRadius = this.width * 0.5 + 'px';
                panel.appendChild(div);
                // 记录当前的蛇
                snakeArr.push(div);
            }
        },
        // 移动
        move: function (food, panel) {
            // 1. 控制蛇的身体移动 (当前的蛇节 移动到 上一个蛇节的位置)
            for (var i = this.body.length - 1; i > 0; i--) {
                this.body[i].x = this.body[i - 1].x;
                this.body[i].y = this.body[i - 1].y;
            }

            // 2. 控制蛇头的移动
            var head = this.body[0];
            switch (this.direction) {
                case 'right':
                    head.x += 1;
                    break;
                case 'left':
                    head.x -= 1;
                    break;
                case 'top':
                    head.y -= 1;
                    break;
                case 'bottom':
                    head.y += 1;
                    break;
            }
        }
    };

5.单独拎出一个Game文件去管理蛇对象以及食物对象,定义Game对象包含食物属性(动态创建食物对象)蛇属性(动态创建蛇对象),并在Game原型定义绘制方法(分别绘制蛇对象和食物对象到面板上的方法)和移动方法(执行蛇移动+方向控制方法)

    function Game(panel) {
        this.food = new Food({});
        this.snake = new Snake({});
        this.panel = panel;
        // console.log(this);
        // 指针赋值
        self = this;
    }

    Game.prototype = {
        constructor: Game,
        render: function () {
           // 1.把食物和蛇绘制到面板上
           this.food.render(this.panel);
           this.snake.render(this.panel);
        },
        run: function () {
            // 1. 蛇移动起来
            snakeMove();
            // 2. 方向控制
           dirControl();
        }
    };

6.Game文件中定义蛇移动(设置一个定时器固定多长时间变化一次并在此方法中进行边界判断)和方向控制(利用键盘事件)的方法

 function snakeMove(){
       var timeId = setInterval(function () {
             // 1. 蛇开始移动和绘制
           self.snake.move(self.food, self.panel);
           self.snake.render(self.panel);

           // 2. 边界控制
           var maxX = self.panel.clientWidth / self.snake.width;
           var maxY = self.panel.clientHeight / self.snake.height;

           // 2.1 获取蛇头的X和Y
           var headX = self.snake.body[0].x;
           var headY = self.snake.body[0].y;

           // 2.2 水平判断
           if(headX < 0 || headX >= maxX){
                clearInterval(timeId);
                if(confirm('很遗憾, 您输了!再来一次?')){
                    // 刷新界面
                    window.location.reload();
                }else {
                    window.close();
                }
           }

           // 2.3 垂直判断
           if(headY < 0 || headY >= maxY){
               clearInterval(timeId);
               if(confirm('很遗憾, 您输了!再来一次?')){
                   // 刷新界面
                   window.location.reload();
               }else {
                   window.close();
               }
           }

       }, 200);
    }

    function dirControl(){
       document.addEventListener('keydown', function (e) {
           // console.log(e['keyCode']);
           /*
             37 - left
             38 - top
             39 - right
             40 - bottom
           */
           switch (e['keyCode']) {
               case 37:
                   self.snake.direction = 'left';
                   break;
               case 38:
                   self.snake.direction = 'top';
                   break;
               case 39:
                   self.snake.direction = 'right';
                   break;
               case 40:
                   self.snake.direction = 'bottom';
                   break;
           }
       }, false);
    }

7.在蛇的移动过程中,注意蛇头是否与食物重叠坐标重叠的判断,如果重叠则让蛇增加一节并再生成一个随机位置的食物

        move: function (food, panel) {
            // 1. 控制蛇的身体移动 (当前的蛇节 移动到 上一个蛇节的位置)
            for (var i = this.body.length - 1; i > 0; i--) {
                this.body[i].x = this.body[i - 1].x;
                this.body[i].y = this.body[i - 1].y;
            }

            // 2. 控制蛇头的移动
            var head = this.body[0];
            switch (this.direction) {
                case 'right':
                    head.x += 1;
                    break;
                case 'left':
                    head.x -= 1;
                    break;
                case 'top':
                    head.y -= 1;
                    break;
                case 'bottom':
                    head.y += 1;
                    break;
            }
            // 3. 判断蛇头是否和食物的坐标重叠
            var headX = head.x * this.width;
            var headY = head.y * this.height;
            // console.log(food.x, food.y);
            // console.log(headX, headY);
            if (headX === food.x && headY === food.y) {
                // 3.1 让蛇增加一节
                var last = this.body[this.body.length - 2];
                this.body.push({
                    x: last.x,
                    y: last.y,
                    color: last.color
                });

                // 3.2 随机在面板上重新生成食物
                food.render(panel);
            }
        }

    };

完整实现github:github.com/missyouzi/t…