2016-11-26 182 views
1

我正在爲未來的瀏覽器遊戲做一個包含canvas的地圖。但是,我在瓷磚和網格生成方面遇到了一些問題。實際上,我的算法有三個步驟:首先用drawImage循環生成背景圖塊(草,海,...),然後生成帶有循環的頂層圖塊(村莊,綠洲......) drawImage再次完成我生成一個moveTo/lineTo循環的網格。用Canvas生成地圖的網格和圖像的問題HTML

爲了說明你這一切,我會告訴你我的算法:

redrawMapContent: function() { 
 
    this.ctx = document.getElementById(this.id).getContext("2d"); 
 

 
    this.drawTilesMap(0, this.ctx); 
 
    this.drawTilesMap(1, this.ctx); 
 
    this.drawGridMap(this.ctx); 
 
    camera.recenterOnMyCity(); 
 
}, 
 

 
drawTilesMap: function(layer, ctx) { 
 
    var tileSize = map.getTileSize(); 
 
    var startCol = Math.floor(camera.x/tileSize); 
 
    var startRow = Math.floor(camera.y/tileSize); 
 
\t  
 

 
    var endCol; var endRow; 
 
    if (camera.width > tileSize * map.cols) endCol = startCol + map.cols - 1; 
 
    else endCol = startCol + (camera.width/tileSize); 
 

 
    if (camera.height > tileSize * map.rows) endRow = startCol + map.rows - 1; 
 
    else endRow = startRow + (camera.height/tileSize); 
 
\t 
 
\t  
 
    var offsetX = -camera.x + startCol * tileSize; 
 
    var offsetY = -camera.y + startRow * tileSize; 
 
     
 
    var imageTilesAtlas = new Image(); 
 
    imageTilesAtlas.onload = function() { 
 
\t  for (var c = startCol; c <= endCol; c++) { 
 
\t \t  for (var r = startRow; r <= endRow; r++) { 
 
\t \t   var tile = map.getTile(layer, c, r); 
 
\t \t   var x = (c - startCol) * tileSize + offsetX; 
 
\t \t   var y = (r - startRow) * tileSize + offsetY; 
 
\t \t   if (tile !== 0) { // 0 => empty tile 
 
\t \t    ctx.drawImage(
 
\t \t    imageTilesAtlas, 
 
\t \t    (tile - 1) * map.defaultTileSize, 
 
\t \t    0, 
 
\t \t    map.defaultTileSize, 
 
\t \t    map.defaultTileSize, 
 
\t \t    Math.round(x), 
 
\t \t    Math.round(y), 
 
\t \t    tileSize, 
 
\t \t    tileSize 
 
\t \t   ); 
 
\t \t   } 
 
\t \t  } 
 
\t  } 
 
    }; 
 
    imageTilesAtlas.src = this.tileAtlas; 
 
}, 
 

 
drawGridMap: function (ctx) { 
 
    var tileSize = map.getTileSize(); 
 
    var width = map.cols * tileSize; 
 
    var height = map.rows * tileSize; 
 
    var x, y; 
 

 
    ctx.strokeStyle = "rgba(100,100,100,0.3)"; 
 

 
    for (var r = 0; r < map.rows; r++) { 
 
\t  x = - camera.x; 
 
\t  y = r * tileSize - camera.y; 
 
\t  ctx.beginPath(); 
 
\t  ctx.moveTo(x, y); 
 
\t  ctx.lineTo(width, y); 
 
\t  ctx.stroke(); 
 
    } 
 
    for (var c = 0; c < map.cols; c++) { 
 
\t  x = c * tileSize - camera.x; 
 
\t  y = - camera.y; 
 
\t  ctx.beginPath(); 
 
\t  ctx.moveTo(x, y); 
 
\t  ctx.lineTo(x, height); 
 
\t  ctx.stroke(); 
 
    } 
 
},

的問題是,有時只有其產生的背景瓷磚。而且,網格永遠不會生成。 我不知道如何解決這個問題,我在控制檯中沒有錯誤,我沒有任何問題。

謝謝你的答案(和抱歉,我的英語水平,我是法國人,它是我第一次張貼在英語論壇)。

回答

0

我有許多問題,加載圖像,直到我用這個模式:

function loadImage(src, callback) { 
    img = document.createElement('img'); 
    img.addEventListener('load', function() { callback(img); } , false); 
    img.src = src; 
} 

function run(sprites) { 
    tileAtlas = []; 
    ctx.drawImage(img,0,0); 
    var counter = 0; 
    for (var y = 0; y < 10; y++){ 
     for (var x = 0; x < 10; x++){ 
       tileAtlas[counter] = ctx.getImageData(
            x * tileSize, 
            y * tileSize, 
            x * tileSize + tileSize, 
            y * tileSize + tileSize); 
       counter++; 
     } 
    } 


    init(); 
    loop(); 

} 

loadImage("sprites.png", run); 

我在這裏: http://codeincomplete.com/posts/javascript-game-foundations-loading-assets/ 我試過你正在使用的方法得當也不太工作。該方法爲加載圖像提供了時間。

至於你的網格,我看着它在JSBIN,似乎只要我代替camera.x和tileSize虛值工作。相機可能有問題嗎?將所有圖塊加載到圖像對象的TilesAtlas數組中可能是更好的方法,每個圖像可以有一個對應於TileAtlas索引的id。這樣你只加載一次。

希望它有幫助..

0

謝謝你的回答。我認爲我用你的loadImage()方法解決了我的tile生成問題:謝謝你。現在,我已經:當所有的瓦片此數組中你怎麼能畫出型動物磚:

loadImage: function (src, ctx) { 
 
\t  img = document.createElement('img'); 
 
\t  img.addEventListener('load', function() { 
 
\t  \t canvas.drawTilesMap(0, ctx, img); // je génère les tiles en background layer de la map 
 
\t \t \t canvas.drawTilesMap(1, ctx, img); // je génère les tiles en top layer de la map 
 
\t  } , false); 
 
\t  img.src = src; 
 
\t }, 
 

 
drawMapContent: function() { 
 
\t \t this.ctx = document.getElementById(this.id).getContext("2d"); 
 
\t \t camera.constructCamera(this.width, this.height); 
 

 
\t \t this.loadImage(this.tileAtlas, this.ctx); 
 
\t \t this.drawGridMap(this.ctx, camera.x, camera.y); // je génère la grille de la map 
 
\t \t 
 
\t \t camera.recenterOnMyCity(); 
 
\t }, 
 

 

 
\t drawTilesMap: function(layer, ctx) { 
 
\t \t var tileSize = map.getTileSize(); 
 
\t \t var startCol = Math.floor(camera.x/tileSize); 
 
\t  var startRow = Math.floor(camera.y/tileSize); 
 
\t  
 
\t  /*********** On empêche l'algo de créer des cases juste pour combler la vue caméra ***********/ 
 
\t  var endCol; var endRow; 
 
\t  if (camera.width > tileSize * map.cols) endCol = startCol + map.cols - 1; 
 
\t  else endCol = startCol + (camera.width/tileSize); 
 

 
\t  if (camera.height > tileSize * map.rows) endRow = startCol + map.rows - 1; 
 
\t  else endRow = startRow + (camera.height/tileSize); 
 
\t  /*********************************************************************************************/ 
 
\t  
 
\t  var offsetX = -camera.x + startCol * tileSize; 
 
\t  var offsetY = -camera.y + startRow * tileSize; 
 

 
\t  for (var c = startCol; c <= endCol; c++) { 
 
\t   for (var r = startRow; r <= endRow; r++) { 
 
\t    var tile = map.getTile(layer, c, r); // recupère le type de case (0, 1, 2, 3, 4, 5 ou 6) 
 
\t    var x = (c - startCol) * tileSize + offsetX; 
 
\t    var y = (r - startRow) * tileSize + offsetY; 
 
\t    if (tile !== 0) { // 0 => empty tile 
 
\t     ctx.drawImage(
 
\t      img, // image contenant les tiles 
 
\t      (tile - 1) * map.defaultTileSize, // x à partir duquel prendre l'image (pour sélectionner la bonne texture) 
 
\t      0, // y à partir duquel prendre l'image (pour sélectionner la bonne texture) 
 
\t      map.defaultTileSize, // source width 
 
\t      map.defaultTileSize, // source height 
 
\t      Math.round(x), // target x 
 
\t      Math.round(y), // target y 
 
\t      tileSize, // target width 
 
\t      tileSize // target height 
 
\t    ); 
 
\t    } 
 
\t   } 
 
\t  } 
 
\t }, 
 

 
\t drawGridMap: function (ctx, cameraX, cameraY) { 
 
\t \t var tileSize = map.getTileSize(); 
 
\t  var width = map.cols * tileSize; 
 
\t  var height = map.rows * tileSize; 
 
\t  var x, y; 
 

 
\t  ctx.strokeStyle = "rgba(100,100,100,0.3)"; // couleur et opacité du quadrillage 
 

 
\t  for (var r = 0; r < map.rows; r++) { 
 
\t   x = - cameraX; 
 
\t   y = r * tileSize - cameraY; 
 
\t   ctx.beginPath(); 
 
\t   ctx.moveTo(x, y); 
 
\t   ctx.lineTo(width, y); 
 
\t   ctx.stroke(); 
 
\t  } 
 
\t  for (var c = 0; c < map.cols; c++) { 
 
\t   x = c * tileSize - cameraX; 
 
\t   y = - cameraY; 
 
\t   ctx.beginPath(); 
 
\t   ctx.moveTo(x, y); 
 
\t   ctx.lineTo(x, height); 
 
\t   ctx.stroke(); 
 
\t  } 
 
\t },

當你說加載在tilesAtlas磚我真的不明白嗎?瀏覽這個數組並在所有索引上使用drawImage()?當你說這種方法會加載圖像一次,我認爲如果你在地圖上移動,你將不得不改變這個數組的內容嗎?

但對於網格,它是如此怪異,我窺探aglorithme並沒有問題:它從線條畫布到畫布的另一邊的一個組成部分。你使用了什麼camera.x和tileSize值?

謝謝你的幫助。

0

也許tilesAtlas是混亂的。我的想法是創建一個圖像陣列,讓我們稱之爲瓷磚。

瓷磚[0]是砂瓦的圖像。瓷磚[1]是一塊 草地磚的圖像。等等

你甚至可以有一個包含Tile屬性的Tile類。然後在世界地圖上,你可以在某處查看數據。

世界[0] [0] = 0。世界[0] [1] = 1

0表示砂瓦。 1表示草地磚。

+0

好的,謝謝你和網格你有什麼想法嗎? – Fortz