2016-11-26 45 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