我正在尝试使用分配给每个方块的随机图像绘制网格。我遇到了绘制序列和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";
}
答案 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存储在一个数组中,让每个图像在加载时独立遍历数组,并在适用的地方只添加本身的副本。
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)
。而且,只要您想将图像添加到图像列表中,只需将其添加到顶部的阵列即可。您不必深入挖掘并修改随机值等等。