22

所以,我制作 HTML5 RPG 只是为了好玩。地图是一个<canvas>(512px 宽,352px 高 | 16 个图块,从上到下 11 个图块)。我想知道是否有更有效的方法来绘制<canvas>.

这是我现在的方式:

如何在地图上加载和绘制图块

使用这幅图块(32x32)绘制地图Image()。图像文件通过一个简单的for循环加载并放入一个名为tiles[]在使用时被绘制的数组中drawImage()

首先,我们加载瓷砖......

在此处输入图像描述

这是如何完成的:

// SET UP THE & DRAW THE MAP TILES
tiles = [];
var loadedImagesCount = 0;
for (x = 0; x <= NUM_OF_TILES; x++) {
  var imageObj = new Image(); // new instance for each image
  imageObj.src = "js/tiles/t" + x + ".png";
  imageObj.onload = function () {
    console.log("Added tile ... " + loadedImagesCount);
    loadedImagesCount++;
    if (loadedImagesCount == NUM_OF_TILES) {
      // Onces all tiles are loaded ...
      // We paint the map
      for (y = 0; y <= 15; y++) {
        for (x = 0; x <= 10; x++) {
          theX = x * 32;
          theY = y * 32;
          context.drawImage(tiles[5], theY, theX, 32, 32);
        }
      }
    }
  };
  tiles.push(imageObj);
}

自然,当玩家开始游戏时,它会加载他们上次离开的地图。但在这里,它是一张全草地图。

现在,地图使用二维数组。这是一个示例地图。

[[4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 1, 1, 1, 1], 
[1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 13, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 13, 11, 11, 11, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 1, 1, 1, 1, 1, 1, 1, 13, 13, 13, 13, 13, 1], 
[1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1]];

我使用简单的if结构得到不同的地图。一旦上面的二维数组return被绘制出来,每个数组中对应的数字就会根据Image()存储在里面进行绘制tile[]。然后drawImage()将发生并根据它xy时间32进行绘制,以在正确的x-y坐标上进行绘制。

多图切换是如何发生的

在我的游戏中,地图需要跟踪五件事:currentIDleftIDrightIDupIDbottomID

  • currentID:您所在地图的当前 ID。
  • leftID:currentID在当前地图左侧退出时要加载的 ID 。
  • rightID:currentID在当前地图右侧退出时加载什么ID 。
  • downID:currentID在当前地图底部退出时要加载的 ID 。
  • upID:currentID在当前地图顶部退出时要加载的 ID 。

需要注意的一点:如果leftIDrightIDupIDbottomID不是特定的,则表示它们是0. 这意味着他们不能离开地图的那一侧。这只是一种无形的封锁。

因此,一旦一个人离开地图的一侧,取决于他们退出的位置......例如,如果他们从底部退出,bottomIDmap加载的数量并因此被绘制在地图上。

这是一个具有代表性的 .GIF,可帮助您更好地可视化:

在此处输入图像描述

正如你所看到的,迟早我会处理很多地图,我会处理很多ID。这可能会变得有点混乱和忙碌。

明显的优点是它一次加载 176 个图块,刷新一个 512x352 的小画布,一次处理一张地图。缺点是 MAP id 在处理许多地图时有时可能会令人困惑。

我的问题

  • 这是存储地图的有效方式(考虑到瓷砖的使用),还是有更好的方式来处理地图?

我在沿着一张巨大的地图思考。地图大小很大,而且都是一个二维数组。然而,视口仍然是 512x352 像素。

这是我(针对这个问题)制作的另一个 .gif 以帮助可视化:

在此处输入图像描述

抱歉,如果您看不懂我的英语。请询问任何您无法理解的内容。希望我说清楚了。谢谢。

4

1 回答 1

17

好吧,这里有一些事情,所以我会按顺序回复它们。


...521 单独的 PNG 文件?

在此处输入图像描述

使用一个。只有一个。也许,上衣。想一想,你让每个客户端发出 500 次 GET 请求只是为了获取游戏的图块?那是疯子。

几乎每个主要站点都使用 spritemap 来减少请求。例如,Youtube 的所有按钮都使用了这张图片:

在此处输入图像描述

你也应该这样做。


从性能的角度来看,您将画布用作视口的概念是正确的。绝对不要让它比它需要的更大!


至于您的地图性能问题,巨型阵列应该可以开始。这是处理它的好方法,除非您的词非常非常大,否则我不会费心探索其他选择。如果它很大,您可能拥有 400x400(左右)的世界“块”,当您到达第 400 行时,您开始使用下一个数组的第 0 行。当然,任何时候“使用”的阵列最多为四个,当然,当您的英雄位于一个不错的旧四个角落之类的位置时。

玩家位置不会很难。如果他在 822、20 块,这意味着他在由(2, 0)(如果我们从 开始(0, 0))表示的块中。具体来说,他将在该区块的第 22、20 个图块中。没有复杂的数学,没有 ID。无需跟踪 ID。您甚至不必跟踪哪个块是最后一个块。你可以只知道总地图大小是(比如说)1200x1200,如果他试图移动到(1201, 50),你甚至不必查看块是否(4, 0)存在。你马上就知道他不能在那里移动,地图只有 1200 格宽!

无论哪种方式,性能都应该很好,并且在您不必担心这个特定数组之前,它实际上将取决于大量其他事情。我的建议是在担心性能之前先考虑制作游戏。游戏变慢后重新审视性能。

一旦你开始表现,我会首先担心除了这个问题之外的所有事情。在画布游戏中,它真的不太可能成为瓶颈。从数组中读取速度很快。已经在内存中的大型数组应该很快。应该没有问题,在它真正出现之前,我不会花时间去期待它。


编辑:视口随播放器移动的示例:http: //jsfiddle.net/kmHZt/10/

于 2012-07-10T04:12:19.667 回答