天天看點

JS 建構對象執行個體

建構一個地圖,

1.需要一個世界類,包含兩個屬性,一個圖例屬性,一個存儲地圖的屬性。

2.需要一個地圖類,地圖類封裝儲存,取出地圖元素的方法,以及存儲地圖。

一個格子類,該類為該格子,x,y坐标。

3.動物類,儲存動物能用方向等資訊。

流程:給世界類輸入地圖和圖例(對象),1,世界類儲存輸入的地圖為地圖類,2,儲存圖例。通過一個foreach函數給該世界對象裡的地圖屬性設定上每個元素,通過一個elementfromchar函數把非空的格子設定成動物類。

給世界添加了以一個屬性tostring,擷取每個地圖類的格子元素,通過charfromelement函數輸出成字元串。

4,添加一個view類為小動物的可視範圍。該類會在世界類調用turn方法裡面的letact方法時調用,也就是在動物移動的時候的才會去看往哪個方向可以移動。

var plan = [
    "############################",
    "#      #    #      o      ##",
    "#                          #",
    "#          #####           #",
    "##         #   #    ##     #",
    "###           ##     #     #",
    "#           ###      #     #",
    "#   ####                   #",
    "#   ##       o             #",
    "# o  #         o       ### #",
    "#    #                     #",
    "############################"];

function Vector(x,y){
    this.x=x;
    this.y=y;
}
Vector.prototype.plus=function (other) {
    return new Vector(this.x+other.x,this.y+other.y);
};

//網格類
function Grid(width,height){
    this.space = new Array(width*height);
    this.width=width;
    this.height=height;
}
Grid.prototype.isInside=function(vector){
    return vector.x >=0 && vector.x < this.width &&
        vector.y >=0 && vector.y < this.height;
};
Grid.prototype.get=function(vector){
    return this.space[vector.x + (vector.y * this.width)];
}
Grid.prototype.set=function(vector,value){
    this.space[vector.x + vector.y * this.width]=value;
}
Grid.prototype.forEach=function(f,context){
    for(var y=0;y<this.height;y++){
        for(var x=0;x<this.width;x++){
            var value=this.space[x + y * this.width];//一會看一下這裡的值,怎麼處理的#
            if(value!=null)
            {
                console.log(value);
                f.call(context, value, new Vector(x,y));
            }

        }
    }
}
var grid=new Grid(5,5);
grid.set(new Vector(1,2),"X");
console.log(grid);

//映射方向
var directions = {
    "n":  new Vector( 0, -1),
    "ne": new Vector( 1, -1),
    "e":  new Vector( 1,  0),
    "se": new Vector( 1,  1),
    "s":  new Vector( 0,  1),
    "sw": new Vector(-1,  1),
    "w":  new Vector(-1,  0),
    "nw": new Vector(-1, -1)
};

//蠢萌小動物對象
function randomElement(array){
    return array[Math.floor(Math.random()*array.length)];
}
var directionNames = "n ne e se s sw w nw".split(" ");

function BouncingCritter(){
    this.direction = randomElement(directionNames);
};
BouncingCritter.prototype.act=function(view){
    if(view.look(this.direction)!=" ")
        this.direction = view.find(" ") || "s";
    return {type: "move", direction : this.direction};
};


function elementFromChar(legend, ch){
    if(ch == " ")
        return null;
    var element = new legend[ch]();//這裡是建立類
    element.origiChar=ch;
    return element;
}
//World對象
function World(map,legend){
    var grid = new Grid(map[0].length, map.length);
    this.grid = grid;
    this.legend = legend;//圖例對象

    map.forEach(function(line, y){
        for(var x=0;x<line.length;x++){
            grid.set(new Vector(x,y),elementFromChar(legend,line[x]));//這裡是無法使用this.grid的
        }
    });
}
//Wall對象占據空間
function Wall(){}

//轉化字元串
function charFromElement(element){
    if(element == null) return " ";
    else return element.origiChar;
}
World.prototype.toString = function(){
    var output="";
    for(var y=0;y<this.grid.height;y++){
        for(var x=0;x<this.grid.width;x++){
            var element = this.grid.get(new Vector(x, y));
            output += charFromElement(element);
        }
        output+="\n";
    }
    return output;
}
        //world 添加turn方法
World.prototype.turn = function(){
    var acted = [];
    this.grid.forEach(function(critter,vector){
        console.log(critter);
        if(critter.act && acted.indexOf(critter)==-1){
            acted.push(critter);
            this.letAct(critter,vector);
        }
    },this);
};
World.prototype.letAct=function(critter, vector){
    var action = critter.act(new View(this, vector));
    if(action && action.type == "move"){
        var dest = this.checkDestination(action, vector);
        if(dest && this.grid.get(dest) == null){
            this.grid.set(vector, null);
            this.grid.set(dest, critter);
        }
    }
};

World.prototype.checkDestination = function(action, vector){
    if(directions.hasOwnProperty(action.direction)){
        var dest=vector.plus(directions[action.direction]);
        if(this.grid.isInside(dest))
            return dest;
    }
}
var world=new World(plan,{'#':Wall,
                            "o":BouncingCritter});
console.log(world.toString());

//定義一個View類為小動物的可視範圍
function View(world,vector){
    this.world = world;
    this.vector = vector;
}
View.prototype.look=function(dir){
    var target = this.vector.plus(directions[dir]);
    if(this.world.grid.isInside(target))
        return charFromElement(this.world.grid.get(target));
    else return '#';
};
View.prototype.findAll=function(ch){
    var found=[];
    for(var dir in directions)
        if(this.look(dir) == ch)
            found.push(dir);
    return found;
}
View.prototype.find=function(ch){
    var found=this.findAll(ch);
    if(found.length == 0) return null;
    return randomElement(found);
};


for(var i=0;i<5;i++){
    world.turn();
    console.log(world.toString());
}