2012-03-07 1006 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() 

}; 

祝你好運!