在循环中绘制多个随机画布图像

时间:2012-04-22 17:44:51

标签: javascript canvas

我正在尝试使用分配给每个方块的随机图像绘制网格。我遇到了绘制序列和Javascript变量可能出现的闭包问题。任何帮助表示赞赏。

var tileSize = 30;
var drawCanvasImage = function(ctx,tile,x,y) {
return function() {
    ctx.drawImage(tile,x,y);
    console.log("x = " + x + "/ y = " + y);
}
}

function textures(ctx) {
var grass = new Image();
var sea = new Image();
var woods = new Image();
for (var i=0; i<=10; i++) {
    for (var j=0; j<=20; j++) {
        rand = Math.floor(Math.random()*3 + 1);
        x = i * tileSize;
        y = j * tileSize;
        if (rand == 1) {
            grass.onload = drawCanvasImage(ctx,grass,x,y);
        } else if (rand == 2) {
            sea.onload = drawCanvasImage(ctx,sea,x,y);
        } else {
            woods.onload = drawCanvasImage(ctx,woods,x,y);
        }
    }
}
grass.src = "textures/grass.png";
sea.src = "textures/sea.png";
woods.src = "textures/woods.png";
}

//function called by the onload event in the html body tag
function draw() {
var ctx = document.getElementById("grid").getContext('2d');
grid(ctx);  //a function to draw the background grid - works fine
textures(ctx);
}

当前结果是三个绘制的图块,全部位于x = 300的位置(相当于10的* i循环* tileSize为30)和随机的y位置。

通过创建变量drawCanvasImage跟踪一个导致并解决(可能是?)闭包问题之后,我至少得到了这三个贴图。

---- ----编辑 工作守则 - 第2次修订:

function randomArray() {
for (var i=0; i<=(xValue/tileSize); i++) {
    terrainArray[i] = [];
    for (var j=0; j<=(yValue/tileSize); j++) {
        rand = Math.floor(Math.random()*4 + 1);
        if (rand == 1) {
            terrainArray[i][j] = 3;
        } else if (rand == 2) {
            terrainArray[i][j] = 2;
        } else if (rand == 3) {
            terrainArray[i][j] = 1;
        } else {
            terrainArray[i][j] = 0;
        }
    }
}
}

var drawTerrain = function(ctx,tile,landUseValue) {
return function() {
    for (var i=0; i<=(xValue/tileSize); i++) {
        for (var j=0; j<=(yValue/tileSize); j++) {
            if (terrainArray[i][j] == landUseValue) {
                ctx.drawImage(tile,i*tileSize,j*tileSize);
            }
        }
    }
}
}

function textures(ctx) {
var grass = new Image();
var sea = new Image();
var woods = new Image();
var desert = new Image();
grass.onload = drawTerrain(ctx,grass,3);
sea.onload = drawTerrain(ctx,sea,0);
woods.onload = drawTerrain(ctx,woods,2);
desert.onload = drawTerrain(ctx,desert,1);
grass.src = "textures/grass.png";
sea.src = "textures/sea.png";
woods.src = "textures/woods.png";
desert.src = "textures/desert.png";
}

2 个答案:

答案 0 :(得分:1)

这是因为每次进行循环时,都会为[image] .onload分配一个新函数,覆盖前一个函数。这就是你最终只得到三张图片的方式。 这应该有效:

if (rand == 1) {
    grass.addEventlistener('load', drawCanvasImage(ctx,grass,x,y), false);
} else if (rand == 2) {
    sea.addEventlistener('load', drawCanvasImage(ctx,sea,x,y), false);
} else {
    woods.addEventlistener('load', drawCanvasImage(ctx,woods,x,y), false);
}

在这里,您只需为每个循环添加一个新的侦听器。

答案 1 :(得分:1)

你在每次迭代中重写三张图像的onload。因此,它只会执行最后添加的onload f或每个图像。

建议:仅在加载thred之后运行绘图方法(并且每次迭代时只调用drawCanvasImage而不使用.onload=

更好:将randoms存储在一个数组中,让每个图像在加载时独立遍历数组,并在适用的地方只添加本身的副本。

对rev 2的改进

function randomArray() {
for (var i=0; i<=(xValue/tileSize); i++) {
    terrainArray[i] = [];
    for (var j=0; j<=(yValue/tileSize); j++) {
        rand = Math.floor(Math.random()*4 + 1);
        terrainArray[i][j] = 4-rand; 
        //OR: replace above two lines with terrainArray[i][j]=Math.floor(Math.random()*4 + 1);. There's no need to have them in exactly reverse order.
    }
}
}

var drawTerrain = function(ctx,tile,landUseValue) {
return function() {
    for (var i=0; i<=(xValue/tileSize); i++) {
        for (var j=0; j<=(yValue/tileSize); j++) {
            if (terrainArray[i][j] == landUseValue) {
                ctx.drawImage(tile,i*tileSize,j*tileSize);
            }
        }
    }
}
}

function textures(ctx) {
var grass = new Image();
var sea = new Image();
var woods = new Image();
var desert = new Image();
grass.onload = drawTerrain(ctx,grass,3);
sea.onload = drawTerrain(ctx,sea,0);
woods.onload = drawTerrain(ctx,woods,2);
desert.onload = drawTerrain(ctx,desert,1);
grass.src = "textures/grass.png";
sea.src = "textures/sea.png";
woods.src = "textures/woods.png";
desert.src = "textures/desert.png";
}

为了使其更加更多灵活,您可以使用数组来存储图像,然后使用length。这样,如果要添加另一个图像,您只需要修改数组。

var srcArray=["textures/grass.png","textures/sea.png","textures/woods.png","textures/desert.png"];
var imgArray=[];
var terrainArray=[];
function textures(ctx){
randomArray();
    for(var i=0;i<srcArray.length;i++){
        imgArray[i]=new Image();
        imgArray[i].src=srcArray[i];
        imgArray[i].onload=drawTerrain(ctx,i);
    }
}
function randomArray() {
for (var i=0; i<=(xValue/tileSize); i++) {
    terrainArray[i] = [];
    for (var j=0; j<=(yValue/tileSize); j++) {
        terrainArray[i][j]=Math.floor(Math.random()*srcArray.length);

    }
}
}

var drawTerrain = function(ctx,index) {
return function() {
    for (var i=0; i<=(xValue/tileSize); i++) {
        for (var j=0; j<=(yValue/tileSize); j++) {
            if (terrainArray[i][j] == index) {
                ctx.drawImage(imgArray[index],i*tileSize,j*tileSize);
            }
        }
    }
}
}

现在,当你想加载所有图像时,你所要做的就是调用terrain(ctx)。而且,只要您想图像添加到图像列表中,只需将其添加到顶部的阵列即可。您不必深入挖掘并修改随机值等等。