最近忙得很少时间上线, 昨天整理代码的时候发现以前学习的时候写的一份贪食蛇.
主要是展示了JS仿面向对象的特性,模拟类的使用,简单的MVC结构.希望对大家有帮助ps:此代码很简单,没有高深的技巧和复杂的结构, 效果也很粗糙(没时间修改),仅供学习和参考之用,而不是什么XXXX版,有不明白的地方欢迎提出
<html>
    <head>
        <style>
            .unit{
                width:20px;
                height:20px;
                position:absolute;
                border:solid 1px black;
            }
            .backlayer{
                width:600px;
                height:600px;
                border:solid 1px gray;
                position:absolute;
                margin:0px;
            }        </style>
        <script language="javascript">
            var $$ = function (id) {
                return "string" == typeof id ? document.getElementById(id) : id;
            };
            var INISBODY=10;  //身体初始长度
            var Global=function(){   //单元格属性
                this.WIDTH=30;
                this.HEIGHT=30;
                this.CELL_SIZE=20;
                return this;
            }
            function fillRect(xpos,ypos,color){
                var backlayer=$$("backlayer");
                var obj=document.createElement("div");
                obj.className="unit";
                obj.style.top=600-ypos*(Global().CELL_SIZE);
                obj.style.left=xpos*Global().CELL_SIZE;
                obj.style.backgroundColor=color;
                backlayer.appendChild(obj);
            }
            function LinkList(){  //模拟链表类
                this.x=[];
                this.y=[];
            }
            LinkList.prototype={
                removeLast:function(){  //移除尾结点
                    var x=this.x.pop();
                    var y=this.y.pop();
                    return [x,y];
                },
                addFirst:function(ret){ //增加头结点
                    var x=[ret[0]];
                    var y=[ret[1]];
                    this.x=x.concat(this.x);
                    this.y=y.concat(this.y);
                },
                getFirst:function(){  //得到头结点
                    return [this.x[0],this.y[0]];
                },
                addLast:function(ret){ //增加尾结点
                    this.x.push(ret[0]);
                    this.y.push(ret[1]);
                },
                getLen:function(){ //得到结点长度
                    return this.x.length;
                }
            }
            function Snake(){ //蛇身类
                this._UP=1;  //4个方向用数字来表示
                this._DOWN=-1;
                this._LEFT=2;
                this._RIGHT=-2;
                this._oldDirection='';  //前次移动方向
                this._newDirection='';  //新移动方向
                this._body=new LinkList(); //蛇身体数据结构
                this.onInit();
            }
            Snake.prototype={
                onInit:function(){  //初始化,蛇在正中间
                    var x = Global().WIDTH / 2;
                    var y = Global().HEIGHT / 2;
                    for (var bodyno = 0; bodyno < INISBODY; bodyno++) {
                        this._body.addLast([x - bodyno, y]);
                    }
                    this._oldDirection = this._newDirection = this._RIGHT;
                    this._life=true;//生命,碰到墙壁或者自身都判定为死(false);
                },
                move:function() { //按方向移动身体,用数据结构来表示就是:增加头结点,移除尾结点
                    if (!(this._oldDirection + this._newDirection == 0)) {//如果和上一次方向相反的话不做任何动作
                        this._oldDirection = this._newDirection;
                    }
                    this._oldTail=this._body.removeLast();
                    var x = this._body.getFirst()[0];
                    var y = this._body.getFirst()[1];
                    switch (this._oldDirection) {
                        case this._DOWN:
                            y--;
                            if (y <=0) {
                                this._life=false;
                            }
                            break;
                        case this._UP:
                            y++;
                            if (y > Global().HEIGHT) {
                                this._life=false;
                            }
                            break;
                        case this._LEFT:
                            x--;
                            if (x < 0) {
                                this._life=false;
                            }
                            break;
                        case this._RIGHT:
                            x++;
                            if (x >= Global().WIDTH) {
                                this._life=false;
                            }
                            break;
                    }
                    var newhead = [x, y];
                    this._body.addFirst(newhead);
                },
                changeDirect:function(direction) { //转换方向
                    this._newDirection = direction;
                },
                eatFood:function() {
                    this._body.addLast(this._oldTail);
                },
                getHead:function(){
                    return this._body.getFirst();
                },
                onDraw:function() { //画出单元格结点所在位置,就是蛇身
                    for(var bodyno=0;bodyno< this._body.getLen(); bodyno++){
                        fillRect(this._body.x[bodyno],this._body.y[bodyno],"blue");
                    }
                },
                isEatBody:function(){ //判断是否吃到身体
                    var isEat=false;
                    for(var bodyno=1;bodyno< this._body.getLen(); bodyno++){
                        if((this._body.x[bodyno]==this.getHead()[0])&&(this._body.y[bodyno]==this.getHead()[1])){
                            isEat=true;
                        };
                    }
                    return isEat;
                },
                isInBody:function(point){ //判断某点是否在身体内,主要是避免产生的食物点在蛇身内
                    var isIn=false;
                    for(var bodyno=0;bodyno< this._body.getLen(); bodyno++){
                        if((this._body.x[bodyno]==point[0])&&(this._body.y[bodyno]==point[1])){
                            isIn=true;
                        };
                    }
                    return isIn;
                },
                isEatGround:function(){//是否撞到墙壁死
                    return !this._life;
                }
            }
            function Food(){ //食物类
                this.x=0;
                this.y=0;
            }
            Food.prototype={
                onDraw:function() {
                    fillRect(this.x,this.y,"red");
                },
                isSnakeEatFood:function(snake) { //判断蛇是否吃到食物,用蛇头点坐标和食物坐标位置判断
                    return (this.x==snake.getHead()[0]&&this.y==snake.getHead()[1]);
                },
                setLocation:function(point){  //设置食物所在位置
                    this.x=point[0];
                    this.y=point[1];
                }
            }
            function Controller(){
                this.snake=new Snake();
                this.food=new Food();
            }
            Controller.prototype={  //控制器类,用来对上面几个对象进行操控,对外进行事件监听
                newGame:function(){
                    var point=this.getFoodLocation();
                    this.food.setLocation(point);
                    this.run();
                },
                changeDirect:function(direction){
                    this.snake.changeDirect(direction);
                },
                getFoodLocation:function(){ //随机获得食物位置,while作用是避免食物出现在蛇身内
                    var point=[];
                    point[0]=parseInt(Math.random()*Global().WIDTH);
                    point[1]=parseInt(Math.random()*Global().HEIGHT)+1;
                    while(this.snake.isInBody(point)){
                        point[0]=parseInt(Math.random()*Global().WIDTH);
                        point[1]=parseInt(Math.random()*Global().HEIGHT)+1;
                    }
                    return point;
                },
                run:function(){
                    this.snake.move();
                    if(this.food.isSnakeEatFood(this.snake)){
                        this.snake.eatFood();
                        var point=this.getFoodLocation();
                        this.food.setLocation(point);
                    }
                    if(this.snake.isEatGround()||(this.snake.isEatBody())){
                        clearTimeout(this._timer);
                        $$("gameover").style.display="block"
                        return;
                    }
                    $$("backlayer").innerHTML='';
                    this.snake.onDraw();
                    this.food.onDraw();
                    this._timer=setTimeout('game.run()',100);
                }
            }
            var game;
            window.onload=function(){
                game=new Controller();
                game.newGame();
                document.onkeydown= function(){
                    var e=window.event||arguments[0];
                    var code=e.keyCode;
                    var dire=(code==37&&2)||(code==38&&1)||(code==39&&-2)||(code==40&&-1);
                    game.changeDirect(dire);
                }
            }
        </script>
    </head>
    <body>
        <div class="backlayer" id="backlayer"></div>
        <div id="gameover" style="position:absolute;left:300px;top:300px;display:none;font-size:30px">Game Over</div>
    </body>
</html>

解决方案 »

  1.   

    这位朋友看得很仔细,确实有这个问题.
    解决办法.把滚动条隐藏掉<body style="overflow:hidden">
      

  2.   

    有个小bug,按其他键(除了上下左右的键)会gameover
      

  3.   

    确实把document.onkeydown的地方改成
                  document.onkeydown= function(){
                        var e=window.event||arguments[0];
                        var code=e.keyCode;
                        var dire=(code==37&&2)||(code==38&&1)||(code==39&&-2)||(code==40&&-1)||0;
                        if(!dire) return false;
                        game.changeDirect(dire);
                    }
      

  4.   


    IE6,7 chrome,FF下测试可用。IE8没测试.
      

  5.   

    晕,我帮你说运行环境:
    桌面-属性-新建-文本文档 ,打开-复制lz的代码到里面,另存为拓展为.html的文件,双击打开 ,即可运行
      

  6.   

    在游戏中(除了上下左右的键)按其他键都会gameover。为什么不把它设定关数呢?