优雅的自动平铺


10

我正在寻找有关人们如何在基于图块的游戏中实现自动平铺的信息。到目前为止,我总是用一堆硬编码的“ if ... else ...”语句来即兴创作,现在我决定是时候找到一些更优雅的解决方案了。我在Internet上搜索了有关该主题的实现示例和讨论的示例,但我只想出了三篇文章:

(特别是最后一个是全面的,非常有帮助。)

我还研究了各种实现和库的文档,例如flixel:http ://www.flixel.org/features.html#tilemaps

可悲的是,我所能找到的所有解决方案与我刚开始时一样,都是即兴且偶然的,几乎从来没有涵盖所有可能的情况。

我正在寻找可以从中学习的自动平铺实现的优雅示例。

Answers:


10

我使用了一种位图方法来应用图块贴图,发现它是一个非常优雅的解决方案。本文提供了一个具体示例,并讨论了如何扩展算法以处理多种地形类型。


看起来像自动平铺的flixel“ AUTO”模式所使用的算法。谢谢,我将其添加到我的列表中。
2013年

3

我本人是通过谷歌搜索这个问题到达这里的,阅读链接的文章,并提出了一个相对紧凑的解决方案,该解决方案生成了一组共47个磁贴。它需要2x3的图块来放置自动倾斜的材料,如下所示:2x3 Autotile Tileset

在左上角有一个单砖变体,在右上角有内角,在底部有四个外角砖(您可以从RPG Maker中识别这种布置)。

诀窍是将每个“逻辑”地图图块分成4个半图块以进行渲染。此外,图块集中的半砖只能在生成的图块中的那个位置,因此左上角的半图块只能在左上角的位置使用。

这些限制意味着您只需要检查每个半砖3个全砖邻居,而不需要检查所有8个相邻砖。

我很快实现了这个想法以进行测试。这是概念验证代码(TypeScript):

//const dirs = { N: 1, E: 2, S: 4, W:8, NE: 16, SE: 32, SW: 64, NW: 128 };
const edges = { A: 1+8+128, B: 1+2+16, C: 4+8+64, D: 4+2+32 };
const mapA = { 0:8, 128:8, 1:16, 8:10, 9:2, 137:18, 136:10, 129:16 };
const mapB = { 0:11, 16:11, 1:19, 2:9, 3:3, 19:17, 18:9, 17:19 };
const mapC = { 0:20, 64:20, 4:12, 8:22, 12:6, 76:14, 72:22, 68:12 };
const mapD = { 0:23, 32:23, 4:15, 2:21, 6:7, 38:13, 34:21, 36:15 };

export function GenerateAutotileMap(_map: number[][], _tile: integer): number[][]
{
    var result = [];
    for (var y=0; y < _map.length; y++) {
        const row = _map[y];
        const Y = y*2;
        // half-tiles
        result[Y] = [];
        result[Y+1] = [];
        // each row
        for (var x=0; x < row.length; x++) {
            // get the tile
            const t = row[x];
            const X = x*2;
            if (t != _tile) continue;
            // Check nearby tile materials.
            const neighbors = (North(_map, x, y) == t? 1:0)
                + (East(_map, x, y) == t? 2:0)
                + (South(_map, x, y) == t? 4:0)
                + (West(_map, x, y) == t? 8:0)
                + (NorthEast(_map, x, y) == t? 16:0)
                + (SouthEast(_map, x, y) == t? 32:0)
                + (SouthWest(_map, x, y) == t? 64:0)
                + (NorthWest(_map, x, y) == t? 128:0);
            // Isolated tile
            if (neighbors == 0) {
                result[Y][X] = 0;
                result[Y][X+1] = 1;
                result[Y+1][X] = 4;
                result[Y+1][X+1] = 5;
                continue;
            }
            // Find half-tiles.
            result[Y][X] = mapA[neighbors & edges.A];
            result[Y][X+1] = mapB[neighbors & edges.B];
            result[Y+1][X] = mapC[neighbors & edges.C];
            result[Y+1][X+1] = mapD[neighbors & edges.D];
        }
    }
    return result;
}    

说明:

  • A是图块的左上部分,B是右上角,C是左下角,D是右下角。
  • edges 保留每个掩码的位掩码,因此我们只能获取相关的邻居信息。
  • map* 是将邻居状态映射到图块图像(0..24)中的图形索引的字典。
    • 因为每个半砖检查3个邻居,所以每个都有2 ^ 3 = 8个状态。
  • _tile 是用于自动平铺的图块。
  • 由于逻辑图块的大小是渲染图块的两倍,因此必须在渲染图中将所有自动坐标(x,y)加倍。

无论如何,这是结果(无论如何只有一个图块):在此处输入图片说明


0

我阅读了大多数链接,并花了一些时间提出另一种解决方案。我不知道它是否好,但是为了模拟RPG Maker VX Ace自动平铺行为(47个图块),我开始执行以下操作:

(左0或1)+(右0或1)+(上0或1)+(下0或1)现在我有5种情况。

如果放置4 =放置图块46

如果3个寄宿生=

如果2 4例+ 2例不确定算法,但没有太多分支。

如果1 =正在处理,但每个方向最终可能会出现4种情况

如果0 =我可以使用链接1、2、4、8中显示的数字算法,并且可以直接使用从1到15的id。

我不是程序员,也不是数学算法最好的程序员,也不是1,2,4,4,8,16,32,64,128解决方案,我也不太喜欢。

也许我的方法至少比这更好。


1
我不确定此答案是否能完全回答问题,您能否再解释一下?如果您引用其他内容,至少可以链接到它吗?
Vaillancourt
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.