2012-03-07 1000 views
4

所以,我想创建一个使用HTML5的minecraft网站主题。我在HTML5/Javascript中有点不稳定(有一段时间没有用过),我需要一些帮助。我正在尝试计算可以放在屏幕上的16x16px数量的瓷砖。然后,为屏幕背景随机“生成地图”。然后,我使用相同的2 for循环来生成地图,以填充画面(在生成过程中分配画面路径)。问题是,画布完全是白色的。任何人都可以挑出问题,如果可能的话给我任何提示?提前致谢!这里是我的HTML5代码:HTML5在画布上使用for循环绘制图片?

<!DOCTYPE html> 
<html> 
    <head> 
     <title>Minecraft Background Check</title> 
    </head> 
    <body> 
     <canvas id="bg" style="position:fixed; top:0; left:0; border:1px solid #c3c3c3; width: 100%; height: 100%;"></canvas> 
     <script type="text/javascript"> 
      "use strict"; 
      var c = document.getElementById("bg"); 
      var ctx = c.getContext("2d"); 
      ctx.canvas.width = window.innerWidth; 
      ctx.canvas.height = window.innerHeight; 

      var width = Math.ceil(window.innerWidth/16); 
      var height = Math.ceil(window.innerHeight/16); 

      for (var x=0;x<width;x++) 
      { 
       for(var y=0;y<height;y++) 
       { 
        var rand = Math.floor(Math.random()*11); 
        var texLoc = getImageNameFromRand(rand,y,height); 

        var img=new Image(); 
        img.onload = function(){ 
         return function() { 
          ctx.drawImage(img,x*16,y*16); 
         }; 
        }; 
        img.src=texLoc; 
       } 
      } 

      function getImageNameFromRand(rand,yVal,maxY) 
      { 
       var dirt = 'dirt.png'; 
       var stone = 'stone.png'; 
       var cobble = 'cobble.png'; 
       var mosscobble = 'mosscobble.png'; 
       var bedrock = 'bedrock.png'; 

       if(yVal===0) 
       { 
        return dirt; 
       } else if(yVal<3) 
       { 
        if(rand < 7) { 
         return dirt; } 
        else { 
         return stone; } 
       } else if(yVal<5) 
       { 
        if(rand < 4) { 
         return dirt; } 
        else { 
         return stone; } 
       } else if(yVal<maxY-2) 
       { 
        if(rand === 0) { 
         return dirt; } 
        else if(rand < 4) { 
         return cobble; } 
        else if(rand < 5) { 
         return mosscobble; } 
        else { 
         return stone; } 
       } else if(yVal<maxY-1) 
       { 
        if(rand < 4) { 
         return bedrock; } 
        else { 
         return stone; } 
       } else if(yVal<maxY) 
       { 
        if(rand < 7) { 
         return bedrock; } 
        else { 
         return stone; } 
       } else { 
        return bedrock; } 
       return bedrock; 
      } 
     </script> 
    </body> 
</html> 

回答

2

这里有很多要解释。我测试了下面的代码并使其能够正常工作,但我一遍又一遍地使用了一张图片。希望这可以在与您的代码合并时起作用。将代码放在下面,代替for循环(即在var height之后和getImageNameFromRand函数之前)。

首先,您的代码定义了全局名称空间中的所有变量,因此每次通过原始循环时都会替换img var以及其src和onload函数等。此外,增加for循环的x和y在onload函数中通过闭包进行引用,但是因为它们只在外部循环期间增加(不在onload函数中),所以它们在onload调用期间都设置为它们的结束值(原始循环运行时的结束值)。

此外,请尝试将所有脚本放入匿名函数中,如(function(){YOUR CODE HERE})()。这样你就不会使用本地变量添加到全局名称空间,并且onload会因为关闭而具有它所需要的。我测试了将所有内容放入匿名函数中,并为我工作。

希望我复制并粘贴这一切都是正确的。请评论它是否关闭。祝你好运!!!

//Copy this code in place of your original "for" loop: 

var imgs = []; 
var imgIndex = 0; 

for (var x = 0; x < width; x++){ 
    for(var y = 0; y < height; y++){ 
     var rand = Math.floor(Math.random() * 11); 
     var texLoc = getImageNameFromRand(rand, y, height); 

     imgs[imgIndex] = new Image(); 

     imgs[imgIndex].onload = (function() { 
      var thisX = x * 16; 
      var thisY = y * 16; 

      return function() { 
       ctx.drawImage(this, thisX, thisY); 
      }; 
     }()); 

     imgs[imgIndex].src = texLoc; 
     imgIndex += 1; 
    } 
} 
1

当你做到以下几点:

img.onload = function(){ 
    return function() { 
     ctx.drawImage(img,x*16,y*16); 
    }; 
}; 

您正试图在img创建一个封闭,因此onload处理程序里面将参考图像,你在该循环的迭代中创建。

但是你并没有那么做。相反,onload处理程序只是定义一个匿名函数,然后什么都不做。

img.onload = function(img){ 
    return function() { 
     ctx.drawImage(img,x*16,y*16); 
    }; 
}(img); 

如果你改变它,让你立即调用匿名函数并传递img,那么你将关闭在img(从for环上下文),它会做你想要什么。

如果没有立即调用外部匿名函数,那么它将成为图像的onload处理程序。没有什么会发生。导致一个空白的画布。

+1

谢谢,但我仍然得到一个空白的画布。还有什么不对吗?再次感谢。 – Flafla2 2012-03-07 01:32:40

+0

您是否检查过画布以确保它占据您期望的空间?例如,我会抛弃'width:100%'和'height:100%',而使用'right:0;底部:0'使它伸展整个窗口(这应该适用于'position:fixed')。否则,还有一大堆你必须做的事情来达到100%的宽度和高度。 – Jeremy 2012-03-07 01:55:36

0

问题是,在你的for循环中,你一直在绘制图像顶部彼此。如果在第一次运行(x = 0,y = 0)后完全跳出forloops,则会在位置0,0上看到随机图像的单个拼贴。当它通过整个double for循环时,最后一个图像将绘制在画布的底部角落,这会创建您所看到的“空白白色画布”。你需要让它画出一张“预填充”的随机拼图画布。这也意味着你的for循环需要放在onload()函数中,因为你的背景只能绘制一次,而不是数百次/数千次。

寻找html5画布图案/瓷砖然后从那里工作。

也,你的onload功能不需要内部功能,你可以把它当作是这样的:

img.onload = function(){ 

    // - nested for loops 
    // -> generate a tile pattern to fit the entire canvas 

    // - ctx.drawImage() 

}; 

祝你好运!