2016-11-26 6 views
1

私は将来のブラウザゲームのためにキャンバスで地図を作成しています。しかし、私はタイルとグリッドの生成にいくつかの問題があります。実際には、アルゴリズムに3つのステップがあります。まず、drawImageのループを使って背景タイル(草、海など)を生成し、ループを使って最上位のタイル(村、オアシスなど)を生成します。 drawImageをもう一度実行して、moveTo/lineToというループでグリッドを生成します。キャンバス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()メソッドで私のタイル生成の問題を解決したと思う:これをありがとう。今、私はしました:すべてのタイルは、この配列にあるときどのようにあなたが貴様のタイルを描くことができます:

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()をすべてのインデックスで参照しますか?そして、このメソッドがイメージを一度ロードすると言うと、マップ上を移動すると、この配列の内容を変更する必要がありますか?

グリッドの場合、それは非常に奇妙です、私はアグロミューティをスパイし、問題はありません。キャンバスのある部分からキャンバスの他の部分に線を引いています。 camera.xとtileSizeのどの値をとったのですか?

ありがとうございました。

0

おそらくtilesAtlasが混乱しています。私の考えは、画像の配列を作成し、それをTilesと呼ぶことです。

タイル[0]は砂のタイルのイメージです。 Tiles [1]は、 芝生タイルの画像です。等

Tileプロパティを含むTileクラスを使用することもできます。そして、世界の地図では、どこかにタイルデータがあります。

ワールド[0] [0] = 0その他[0] [1] = 1

0砂タイルを表します。 1は芝生タイルを示す。

+0

ありがとうございました。グリッドはありますか? – Fortz

関連する問題