手写贪吃蛇

html:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <link rel="stylesheet" type="text/css" href="css/index.css" />
        
    </head>
    <body>
        <div class="opt-box">
            <h3>无敌贪吃蛇</h3>
            
            <p style="font-size: 12px ;">空格暂停,暂停后按方向键继续。</p>
            <p style="font-size: 12px ;">可选择select框选择地图大小并点击start开始</p>
            <p style="font-size: 12px ;">刷新浏览器从新开始</p>
            
            <span>类型</span>
            <select class="select-1" name="">
                <option value="small">small</option>
                <option value="middle">middle</option>
                <option value="big">big</option>
            </select>
            <button class="start">start</button>
            <button class="stop">stop</button>
            <div class="score">
            <span>50</span>分
            </div>
        </div>        
        <div class="main" style="display: none;">
            <div class="snake-box">                
                <div class="s s0"></div>
                <div class="s s1"></div>
                <div class="s s2"></div>
                <div class="s s3"></div>
                <div class="s s4"></div>                
            </div>
            <div class="o-box">
                <!--
                <div class="o"></div>
                <div class="o"></div>
                <div class="o"></div>
                -->
            </div>        
        </div>
        <script src="js/jquery-2.1.4.min.js" type="text/javascript" charset="utf-8"></script>
        
        <script src="js/snake.js" type="text/javascript" charset="utf-8"></script>

        <script type="text/javascript">
            new Snake("main", "select-1", "start", "score","stop");
        </script>
        
    </body>
</html>

css:

* {
  margin: 0;
  padding: 0;
}
.opt-box {
  width: 400px;
  height: 100px;
  text-align: center;
  border: 1px solid #ddd;
  margin: 0 auto;
}
.opt-box .score {
  float: right;
}
.main {
  border: 1px solid #eee;
  margin: 0 auto;
  position: relative;
}
.main.small {
  width: 400px;
  height: 400px;
}
.main.middle {
  width: 600px;
  height: 600px;
}
.main.big {
  width: 800px;
  height: 800px;
}
.main .o-box {
  width: 100%;
  height: 100%;
  background: darkcyans;
  position: absolute;
  z-index: -5;
  top: 0;
  left: 0;
}
.main .o-box .o {
  width: 9px;
  height: 9px;
  float: left;
  border-bottom: 1px solid #ddd;
  border-right: 1px solid #ddd;
}
.main .snake-box {
  width: 100%;
  height: 100%;
  position: absolute;
  top: -1px;
  z-index: -4;
}
.main .snake-box .c {
  width: 10px;
  height: 10px;
  background: darkblue;
  position: absolute;
  z-index: -1;
}
.main .snake-box .s {
  width: 10px;
  height: 10px;
  background: red;
  position: absolute;
  top: 200px;
}
.main .snake-box .s.s0 {
  background: darkcyan;
  z-index: 100000;
}
.main .snake-box .s.s1 {
  z-index: 1;
}
.main .snake-box .s.s2 {
  z-index: 2;
}
.main .snake-box .s.s3 {
  z-index: 3;
}
.main .snake-box .s.s4 {
  z-index: 4;
}

js:

/*
 Created by lianxiaozhuang;
 Snake Game;
  created-start-time:2017/3/30;
  end-time:2017/4/17;
 * */
;
(function(win, doc, $, undefined) {
    var Snake = function(main, sele, start, score, stop) {
        this.author = "lianxiaozhuang";
        this.main = $("." + main); //div
        this.sele = $("." + sele); //select下拉框
        this.start = $("." + start); //开始按钮
        this.stop = $("." + stop); //开始按钮
        this.scoreSpan = $("." + score).find("span"); //分数    容器
        this.score = "0"; //初始化分数
        this.snakeWidth = 10; //默认食物或者蛇身身宽度(和css样式中的保持一样)
        this.snakeNum = 5; //当前蛇身个数
        this.speed = 50; //移动一格所用时间(大于0)
        this.speedGap = 50; //移动与下一格的时间间隔(大于0)
        this.timer = null; //当前执行动画的定时器;
        this.dir = { //当前蛇头方向
            up: false,
            down: false,
            left: false,
            right: true
        };
        this.secondKey = { //防止二次按键导致定时器累加
            up: true,
            down: true,
            left: false,
            right: true
        };
        this.snakeBodyArr = [ //蛇身位置容器
            {top: "200px",left: "210px"},
            {top: "200px",left: "200px"},
            {top: "200px",left: "190px"},
            {top: "200px",left: "180px"},
            {top: "200px",left: "170px"}
        ];
        this.init();
    }
    Snake.prototype = {
        constructor: Snake,
        init: function() {
            var _this = this;
            var start = function() {
                doc.onkeydown = function(evt) {
                    var e = win.event || evt;
                    _this.keyBoardEvent(e); //keyBoardEvent键盘事件中获取不到实例的this,用参数传进来
                }
            };
            _this.start.click(function() { //点击开始
                _this.scoreSpan.html(_this.score); //初始化分数
                var _val = _this.sele.val();
                _this.render(_val); //传参绘制画布;初始化蛇 与食物
                start();
            });
            _this.start.click(); //测试用;默认刚加载页面时 点击了开始按钮
            _this.stop.click(function() {
                clearInterval(_this.timer);
            })
        },
        render: function(_val) { //绘制画布;初始化蛇 与食物
            var _this = this;
            var $s = _this.main.find(".s");
            var j = 0,
                html = "",
                classN = "";
            var $obox = this.main.find(".o-box");
            if(_val == "small") {
                j = 400;
                classN = "small";
            } else if(_val == "middle") {
                j = 600;
                classN = "middle";
            } else if(_val == "big") {
                j = 800;
                classN = "big";
            }
            for(var i = 0; i < j * j / 100; i++) {
                html += '<div class="o"></div>'
            }
            this.main.removeClass("small middle big").addClass(classN);
            $obox.html(html);
            this.main.hide().show();
            this.main.find(".snake-box .c").remove();
            this.main.find(".snake-box").append($('<div class="c"></div>'));        
            
            $s.each(function(index, element) {//初始化蛇身
                $(element).css({
                    "top": _this.snakeBodyArr[index].top,
                    "left": _this.snakeBodyArr[index].left
                });
            });
            this.foodRadomPosition(); //食物随机位置
        },
        foodRadomPosition: function() { //食物的随机位置设置,若与蛇身重合重新设置
            var _this = this,m = Math,
                $snakeleft, $snaketop, //蛇身每一方块相对与盒子的位置
                dleft, dtop, //蛇与食物的距离
                $top, $left; //食物随机位置
            var lap = false; //食物与蛇不重合
            var $s = _this.main.find(".s"); //蛇身
            var $c = _this.main.find(".c"); //食物
            var _snake_box = _this.main.find(".snake-box"); //snake-box
            var _snake_box_left = _snake_box.offset().left,
                _snake_box_top = _snake_box.offset().top; //snake-box的位置
            //递归实现 生成满足要求的随机位置
            var radomSet = function() {
                    lap = false; //循环调用时初始化       "是否重合标志"  ,防止死循环
                    $top = _this.radomNum(), //每一次递归调用的随机数都不一样
                        $left = _this.radomNum();
                    //console.log($top+" "+$left);                    
                    $s.each(function(index, element) {
                            var _left = $(element).offset().left; //对蛇的每一个方块循环;当前块相对于window的位置_left和_top
                            var _top = $(element).offset().top;
                            $snakeleft = _left - _snake_box_left; //蛇相对于snake-box的left值 $snakeleft
                            $snaketop = _top - _snake_box_top;
                            //食物与蛇身 距离 绝对值
                            dleft = m.abs($snakeleft - $left), dtop = m.abs($snaketop - $top);
                            //console.log(dleft+" "+dtop);
                            if(dleft < _this.snakeWidth && dtop < _this.snakeWidth) { //食物与蛇身left 与 top同时小于自身高度,重合                                    
                                //console.log("有重合");
                                lap = true; //重合
                                return false; //有重合;跳出循环                                    
                            }
                        }) //end each                                    
                    if(!lap) { //若第一组随机数满足要求;直接返回位置数的对象
                        //console.log("生成位置对象")
                        return {
                            "$top": $top,
                            "$left": $left
                        }
                    } else { //若第一组随机数不满足要求(蛇与食物重合),则递归调用                        
                        return radomSet();
                    }
                } //end radomSet    
            var tempPositionObj = radomSet(); //获取生成的 位置对象;
            $c.css({ //利用radomSet()返回的对象  ; 设置食物的位置
                "top": tempPositionObj.$top,
                "left": tempPositionObj.$left
            }).show();
        },
        radomNum: function() { //食物top和left值得随机位置数(不超出画布),返回值 供radomPosition调用
            var m = Math;
            var _width = this.main.width();
            return m.max(0, parseInt(m.random() * _width / 10) * 10 - 10)
        },
        getCeil: function(a) { //蛇头坐标值向上取整(防止取得值为小数)
            return a % 10 == 0 ? a : 10 * (parseInt(a / 10) + 1)
        },
        getFloor: function(a) { //向下取整
            return a % 10 == 0 ? a : 10 * (parseInt(a / 10))
        },
        changeDirection: function(direc) { //按不同方向键后改变走向
            var _this = this;
            var $top, $left;
            var $s0 = this.main.find(".s0"); //蛇头
            if(direc == "up") { //上上上上上上上上上上上上上上上上上上上上上上上上上上上上上上上                    
                _this.secondKeySet("up"); //一旦按下;设置标记                                            
                if(_this.secondKey.up) {
                    clearInterval(_this.timer);
                    _this.secondKey.up = _this.secondKey.down = false; //防止二次按up键导致定时器叠加//防止倒退
                    _this.timer = setInterval(function() {
                        $top = $s0.position().top - 10;
                        if(_this.dir.left) {
                            $left = _this.getFloor($s0.position().left);
                        } else if(_this.dir.right) {
                            $left = _this.getCeil($s0.position().left);
                            //console.log($left)
                        }
                        //首次
                        else if(_this.dir.up){
                            $left = $s0.position().left
                        }
                        _this.dirSet("up")
                        //
                        _this.eatFood($top, $left);
                        _this.animateSnake($top, $left);
                    
                    }, _this.speedGap + _this.speed + 100)
                }
            } else if(direc == "down") { //下下下下下下下下下下下下下下下下下下下下下下下下下下下下下
                _this.secondKeySet("down");
                if(_this.secondKey.down) {
                    clearInterval(_this.timer);
                    _this.secondKey.up = _this.secondKey.down = false; //防止二次按up键导致定时器叠加//防止倒退                                                                                        
                    _this.timer = setInterval(function() {
                        $top = $s0.position().top + 10;
                        if(_this.dir.left) {
                            $left = _this.getFloor($s0.position().left);
                        } else if(_this.dir.right) {
                            $left = _this.getCeil($s0.position().left);
                        }
                        //
                        else if(_this.dir.down){
                            $left = $s0.position().left
                        }
                        _this.dirSet("down")
                        //
                        _this.eatFood($top, $left);
                        _this.animateSnake($top, $left);
                        
                    }, _this.speedGap + _this.speed + 100)
                }
            } else if(direc == "left") { //左左左左左左左左左左左左左左左左左左左左左左左左左左
                _this.secondKeySet("left");
                if(_this.secondKey.left) {
                    clearInterval(_this.timer);
                    _this.secondKey.right = _this.secondKey.left = false; //防止二次按键导致定时器叠加                                                                                
                    _this.timer = setInterval(function() {
                        $left = $s0.position().left - 10;
                        if(_this.dir.up) {
                            $top = _this.getFloor($s0.position().top);
                        } else if(_this.dir.down) {
                            $top = _this.getCeil($s0.position().top);
                        }
                        //
                        else if(_this.dir.left){
                            $top = $s0.position().top
                        }
                        _this.dirSet("left")
                        //
                        _this.eatFood($top, $left);
                        _this.animateSnake($top, $left);
                    }, _this.speedGap + _this.speed + 100)
                }
            } else if(direc == "right") { //右右右右右右右右右右右右右右右右右右右右右右右右右右右右右右右右右右                
                _this.secondKeySet("right");
                if(_this.secondKey.right) {
                    clearInterval(_this.timer);
                    _this.secondKey.right = _this.secondKey.left = false; //防止二次按键导致定时器叠加                                                                                                                                                                                    
                    _this.timer = setInterval(function() {
                        $left = $s0.position().left + 10;
                        if(_this.dir.up) {
                            $top = _this.getFloor($s0.position().top);
                        } else if(_this.dir.down) {
                            $top = _this.getCeil($s0.position().top);
                        }
                        //
                        else if(_this.dir.right){
                            $top = $s0.position().top
                        }
                        _this.dirSet("right")
                        //
                        _this.eatFood($top, $left);
                        _this.animateSnake($top, $left);
                    }, _this.speedGap + _this.speed + 100)
                }
            }
        },
        eatFood: function($top, $left) {
        
            var _this = this;
            var $s0 = this.main.find(".s0"); //蛇头
            var $c = _this.main.find(".c"); //食物
            var _snake_box = _this.main.find(".snake-box"); //snake-box
            var $last = _snake_box.find(".s:last");
            var $last_top = _this.getFloor($last.position().top),
                $last_left = _this.getFloor($last.position().left);            
            var dtop = $s0.position().top - $c.position().top,
                dleft = $s0.position().left - $c.position().left;        
            if(dtop==0 && dleft== 0) {//吃
                $c.hide();
                _snake_box.append($('<div class="s" style="z-index:' + _this.snakeNum + '"></div>').css({
                    top: $last_top,
                    left: $last_left
                }));
                _this.snakeBodyArr.unshift({top: $top,left: $left});
                _this.foodRadomPosition();
                _this.snakeNum++;
                _this.score++;
                _this.scoreSpan.html(_this.score);
                if(_this.score>=5){//修改速度
                    _this.speed = 20;
                    _this.speedGap = 10;
                }else if(_this.score>=10){//修改速度
                    _this.speed = 5;
                    _this.speedGap = 0;
                }
            }
        },
        animateSnake: function($top, $left) {
            var _this = this;
            var $s0 = this.main.find(".s0"); //蛇头
            var _width =  this.main.width()-this.snakeWidth;
            var $s = this.main.find(".s"); //蛇身
            _this.snakeBodyArr.pop();
            _this.snakeBodyArr.unshift({top: $top,left: $left});
            var _left = $s0.position().left,_top = $s0.position().top;
            if(_top<0||_left<0||_top>_width||_left>_width){//游戏结束
                clearInterval(_this.timer);
                alert("game over!");
                return;
            }
            
            $s.each(function(index, element) {
                $(element).animate({
                    "top": _this.snakeBodyArr[index].top,
                    "left": _this.snakeBodyArr[index].left
                }, _this.speed);
            });
            
        },
        dirSet: function(flag) {
            var _this = this;
            if(flag == "up") {
                _this.dir.up = true;
                _this.dir.down = false;
                _this.dir.left = false;
                _this.dir.right = false;
            } else if(flag == "down") {
                _this.dir.up = false;
                _this.dir.down = true;
                _this.dir.left = false;
                _this.dir.right = false;
            } else if(flag == "left") {
                _this.dir.up = false;
                _this.dir.down = false;
                _this.dir.left = true;
                _this.dir.right = false;
            } else if(flag == "right") {
                _this.dir.up = false;
                _this.dir.down = false;
                _this.dir.left = false;
                _this.dir.right = true;
            }
        },
        secondKeySet: function(mark) { //相对于当前移动方向的    “左边与右边方向 ”   的 二次按键标记
            var _this = this;
            if(mark == "up" || mark == "down") {
                _this.secondKey.left = true;
                _this.secondKey.right = true;
            } else if(mark == "left" || mark == "right") {
                _this.secondKey.up = true;
                _this.secondKey.down = true;
            }
        },
        keyBoardEvent: function(e) {            
            var _key = e.keyCode || e.which;  
            var _this = this;
            switch(_key) {    
                case 37: //左键                    
                    _this.changeDirection("left");    
                    break;    
                case 38: //向上键                    
                    _this.changeDirection("up");
                    break;    
                case 39: //右键                    
                    _this.changeDirection("right");    
                    break;    
                case 40: //向下键                    
                    _this.changeDirection("down");   
                    break;    
                case 13: //回车键                     
                    alert("暂停"); 
                    break;
                case 32: //空格                    
                    clearInterval(_this.timer) ;
                    break;
                default:                    
                    _this.changeDirection("right");   
                    break;
            }  
        }

    }
    win.Snake = Snake;
}(window, document, jQuery))

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏腾讯Bugly的专栏

Android之实现妙趣横生的粘连布局

1概述 在手机QQ中,有一个功能叫“一键下班”,无论界面有多少信息,只要你不想看,就可以手指一滑,将他们全部消灭。据说这个功能专为红点恐惧症、信息阅读强迫症以及...

36830
来自专栏GIS讲堂

当我们遇到问题的时候改如何解决

问题 在Openlayer3中直接加载PNG图片,在API中提供了ImageStatic可以将图片展示出来,但是如何设置图片的imageExtent让图片能...

18620
来自专栏陈满iOS

iOS图形处理概论:OpenGL ES,Metal,Core Graphics,Core Image,GPUImage,Scene Kit (3D) ,Sprite Kit (2D),OpenCV

对于刚接触iOS图形相关框架的小白,有一些图形框架在字面上和功能上非常容易混淆。这里旨在总结一下各种框架,区分它们的概念和功能,以作日后进一步细分学习的指引。因...

45030
来自专栏数据小魔方

数据透视表入门

今天跟大家分享有关数据透视表入门的技巧! 数据透视表是excel附带功能中为数不多的学习成本低、投资回报率高、门槛低上手快的良心技能! 对于日程的排序、汇总、...

40560
来自专栏LET

数据可视化之MarkPoint

23650
来自专栏前端小作坊

CSS硬件加速的好与坏

每个人都痴迷于60桢每秒的顺滑动画。为了实现这个顺滑体验现在用的最流行的一个做法就是使用『CSS硬件加速』。在一些极端例子中,强制使用translate3d意味...

11120
来自专栏点滴积累

Cesium基础使用介绍

前言 最近折腾了一下三维地球,本文简单为大家介绍一款开源的三维地球软件——Cesium,以及如何快速上手Cesium。当然三维地球重要的肯定不是数据显示,这只是...

2.1K60
来自专栏BestSDK

表格设计的六种打开方式,正确提升表格的阅读效率

在设计数据类产品、后台配置产品时,PD 常常会指着一块地方说「这儿放个表格,需要有balabala…」,而表格的结构不外乎这几种类型: 垂直布局 水平布局 矩阵...

32950
来自专栏编程

前端开发者常用的 9个JavaScript 图表库

英文: Anton Shaleynikov 译文:葡萄城控件 www.cnblogs.com/powertoolsteam/p/top-9-javascri...

40750
来自专栏大数据文摘

手把手 | 教你爬下100部电影数据:R语言网页爬取入门指南

30270

扫码关注云+社区

领取腾讯云代金券