エレガントな自動タイル


10

タイルベースのゲームでオートタイルを実装する方法についての情報を探しています。これまでのところ、ハードコーディングされた「if ... else ...」ステートメントの束を使ってそれを常に即興で表現してきましたが、今はよりエレガントな解決策を見つける時がきたと判断しました。自動タイル張りの実装の例とトピックに関するディスカッションをインターネットで検索しましたが、3つの記事しか思いつきませんでした。

(特に最後のものは包括的で非常に役立ちます。)

私もそれを実装することを、様々な実装とライブラリのドキュメントを見てきた、例えば、flixel:http://www.flixel.org/features.html#tilemaps

悲しいことに、私が見つけたすべての解決策は、私が始めたときとまったく同じように即興で無計画であり、考えられるすべてのケースをカバーすることはほとんどありません。

私は学ぶことができるオートタイリング実装のエレガントな例を探しています。

回答:


10

私はタイルマップ適用するためにビットごとの方法を使用し、それが非常にエレガントなソリューションであることがわかりました。この記事では具体的な例を示し、アルゴリズムを拡張して複数の地形タイプを処理する方法について説明します。


これは、自動タイル分割のフリクセル「AUTO」モードで使用されるアルゴリズムのように見えます。ありがとう、私はそれを私のリストに追加しています。
Radomir Dopieralski、2013年

3

私はこの問題を自分でグーグルしてここに到着し、リンクされた記事を読んで、47タイルの共通セットを生成する比較的コンパクトなソリューションを作成しました。次のような自動タイルマテリアルには2x3タイルセットが必要です。2x3オートタイルタイルセット

左上にシングルタイルバリアント、右上に内側のコーナー、下部に4つの外側のコーナータイルがあります(RPG Makerでこの配置を確認できます)。

トリックは、各「論理」マップタイルをレンダリング用に4つのハーフタイルに分割することです。さらに、タイルセットのハーフタイルは、生成されたタイルのその位置にしか配置できないため、左上ハーフタイルは左上位置でのみ使用できます。

これらの制限は、8つの隣接するタイルすべてではなく、ハーフタイルごとに3つのフルタイルの近傍のみをチェックする必要があることを意味します。

私はこのアイデアをすぐに実装してテストしました。以下が概念実証コード(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 自動タイル化の対象となるタイルです。
  • 論理タイルはレンダリングタイルの2倍であるため、すべてのオートタイル座標(x、y)をレンダリングマップで2倍にする必要があります。

とにかく、ここに結果があります(とにかくタイルが1つだけ):ここに画像の説明を入力してください


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、8、16、32、64、128のソリューションはあまり好きではありません。

多分私のアプローチは少なくともそれよりも優れています。


1
この答えが質問に完全に答えているかどうかはわかりませんが、もう少し説明してもらえますか?他に言及している場合、少なくともそれにリンクできますか?
Vaillancourt
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.