JavaScript实现的贪吃蛇算法及其研究(四)

内容接上一章JavaScript实现的贪吃蛇算法及其研究(三).

关于Snake类的代码已经编写完毕了,World也已经编写完毕,整个贪吃蛇游戏中仅剩下Food的生成代码没有编写,本篇作为该系列关于算法的最后一篇,将编写用于生成Food坐标的方法generate.

generate方法

对于贪吃蛇游戏而言,Food在World上只同时存在一个,所以每当Snake吃掉一个Food时,便会触发该方法生成下一个Food的坐标.

对于生成坐标,使用Math.random函数进行随机就可以了,但由于牵涉到贪吃蛇的游戏规则,又显得不那么简单:

食物不能生成在蛇上

因为这条规则,导致无法使用常规的方法随机生成食物的坐标,为了解决这一问题,需要开拓新的思路.

摆在眼前的解决方法有三种:

  1. 排除蛇头和蛇身所占用的坐标,对剩余可用的坐标进行随机.
  2. 对行与列进行遍历然后随机,最后排除蛇头和蛇身的坐标.
  3. 采用简单的随机方法,如果被蛇头和蛇身占用,则再次进行随机.

这三种方法中,第3种是不可取的,因为在蛇身增长到一定程度后,随机失败的几率就会大幅增加,大量的重复随机可能会造成游戏卡顿.第2种的效率最高,但实施较为麻烦,所以我们采用第1种方式.

无论如何都要使用到Snake的数据,我们需要在generate方法的参数中加上snake,并在调用generate方法的地方传入snake对象.

代码如下:

var head=snake.head.get(),  
    part=snake.body.part;
var map=[]  
for(var x=0;x<World.Size.width;x++){  
    for(var y=0;y<World.Size.height;y++){
        if(x==head.x && y==head.y){
            continue;
        }
        if(part.length>0){
            var pass=true;
            for(var i=part.length;i--;){
                if(x==part[i].x && y==part[i].y){
                    pass=false;
                    break;
                }
            }
            if(pass){
                map.push([x,y]);
            }
        }else{
            map.push([x,y]);
        }
    }
}
var i=Math.floor(Math.random()*map.length);  
World.Food.x=map[i][0];  
World.Food.y=map[i][1];  

这段代码首先对整个World的每一个坐标点进行遍历,排除被蛇头和蛇身占据的坐标点,将可用的坐标点存入数组map,最后对map的索引进行随机,最后确定坐标点作为食物的坐标.

Next

整个贪吃蛇的代码如下所示,剩余的部分细节将在下章进行补充.

var World={  
    Size:{
        width:20,
        height:20
    }
    Food:{
        x:undefined,
        y:undefined,
        generate:function(snake){
            var head=snake.head.get(),
                part=snake.body.part;
            var map=[]
            for(var x=0;x<World.Size.width;x++){
                for(var y=0;y<World.Size.height;y++){
                    if(x==head.x && y==head.y){
                        continue;
                    }
                    if(part.length>0){
                        var pass=true;
                        for(var i=part.length;i--;){
                            if(x==part[i].x && y==part[i].y){
                                pass=false;
                                break;
                            }
                        }
                        if(pass){
                            map.push([x,y]);
                        }
                    }else{
                        map.push([x,y]);
                    }
                }
            }
            var i=Math.floor(Math.random()*map.length);
            World.Food.x=map[i][0];
            World.Food.y=map[i][1];
        }
    }
}

var Direction={  
    up:1,
    right:2,
    down:-1,
    left:-2
};

function Snake(){  
    var self=this;

    function Head(){
        this.x=9;
        this.y=9;
        this.direction=undefined;
        this.move=function(direction){
            var head={
                x:this.x,
                y:this.y
            };
            if(direction+this.direction==0){
                direction=this.direction;
            }
            this.direction=direction;
            switch(direction){
                case Direction.up:
                    this.y--;
                    break;
                case Direction.right:
                    this.x++;
                    break;
                case Direction.down:
                    this.y++;
                    break;
                case Direction.left:
                    this.x--;
            }
            if(eat(this.x,this.y)){
                self.body.increase(head);
                World.Food.generate(self);
            }else   if(hitCheck(this.x,this.y) || eatSelfCheck(this.x,this.y)){

            }else{
                self.body.move(head);
            }
        };
        function eat(x,y){
            if(x==World.Food.x && y==World.Food.y){
                return true;
            }else{
                return false;
            }
        }
        function hitCheck(x,y){
            if(x<0 || y<0 || x==World.Size.width || y==World.Size.height){
                return true;
            }else{
                return false;
            }
        }
        function eatSelfCheck(x,y){
            var part=self.body.part;
            for(var i=part.length;i--;){
                if(x==part[i].x && y==part[i].y){
                    return true;
                }
            }
            return false;
        }
    }

    function Body(){
        this.part=[];
        this.move=function(head){
            if(this.part.length>0){
                this.part.pop();
                this.increase(head);
            }
        };
        this.increase=function(head){
            this.part.unshift(head);
        };
    }

    this.body=new Body();
    this.head=new Head();
}
var snake=new Snake();  

在下一章中,我们将使用HTML5使这个贪吃蛇游戏变得可玩.

JavaScript实现的贪吃蛇算法及其研究(五)