Autotiling yang elegan

10

Saya mencari informasi tentang bagaimana orang menerapkan autotiling dalam game berbasis ubin mereka. Sejauh ini saya selalu mengimprovisasinya dengan banyak pernyataan "jika ... lain ..." yang sudah dikodekan, dan sekarang saya memutuskan bahwa inilah saatnya untuk menemukan solusi yang lebih elegan. Saya pergi mencari di internet untuk contoh implementasi autotiling dan diskusi tentang topik, tetapi saya hanya menghasilkan tiga artikel:

(Terutama yang terakhir komprehensif dan sangat membantu.)

Saya juga telah melihat berbagai implementasi dan dokumentasi perpustakaan, yang mengimplementasikannya, misalnya, flixel: http://www.flixel.org/features.html#tilemaps

Sedihnya, semua solusi yang saya dapat temukan adalah persis seadanya dan seadanya, seperti apa yang saya mulai, dan hampir tidak pernah mencakup semua kasus yang mungkin.

Saya mencari contoh elegan implementasi autotiling yang bisa saya pelajari.

Radomir Dopieralski
sumber

Jawaban:

10

Saya telah menggunakan Metode Bitwise Untuk Menerapkan Tilemaps dan menemukan itu menjadi solusi yang sangat elegan. Artikel ini memberikan contoh nyata dan membahas cara memperluas algoritme untuk menangani beberapa jenis medan.

NoobsArePeople2
sumber
Ini terlihat seperti algoritma yang digunakan oleh mode autotiling flixel "AUTO". Terima kasih, saya menambahkannya ke daftar saya.
Radomir Dopieralski
3

Saya tiba di sini dengan Googling masalah ini sendiri, membaca artikel yang ditautkan, dan menghasilkan solusi yang relatif ringkas yang menghasilkan 47 ubin. Ini membutuhkan 2x3 tileset untuk bahan autotiled seperti ini:tileset autotile 2x3

Dengan varian ubin tunggal di kiri atas, sudut dalam di kanan atas, dan empat ubin sudut luar di bagian bawah (Anda dapat mengenali pengaturan ini dari RPG Maker).

Caranya adalah memecah setiap ubin peta "logis" menjadi 4 ubin setengah untuk dirender. lebih jauh lagi, setengah ubin di ubin hanya dapat berada di posisi itu di ubin yang dihasilkan, sehingga ubin setengah kiri atas hanya dapat digunakan di posisi kiri atas.

Pembatasan ini berarti bahwa Anda hanya perlu memeriksa 3 tetangga ubin penuh per ubin setengah, bukan semua 8 ubin tetangga.

Saya mengimplementasikan ide ini dengan cepat untuk mengujinya. Berikut kode proof-of-concept (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;
}    

Penjelasan:

  • Aadalah bagian kiri atas ubin, Badalah kanan atas, Cadalah kiri bawah, Dadalah kanan bawah.
  • edges memegang bitmasks untuk masing-masing, sehingga kami hanya dapat mengambil info tetangga yang relevan.
  • map* adalah kamus yang memetakan negara tetangga ke indeks grafik pada gambar tileset (0..24).
    • karena setiap ubin setengah memeriksa 3 tetangga, masing-masing memiliki 2 ^ 3 = 8 negara.
  • _tile adalah ubin yang ditargetkan untuk autotiling.
  • Karena petak logis kami dua kali lebih besar dari petak rendering kami, semua autotile coords (x, y) harus digandakan dalam peta rendering.

Bagaimanapun, berikut hasilnya (dengan hanya satu ubin, toh):masukkan deskripsi gambar di sini

Pennie Quinn
sumber
0

Saya membaca sebagian besar tautan dan meluangkan waktu untuk mencari solusi lain. Saya tidak tahu apakah ini baik atau tidak, tetapi untuk mensimulasikan perilaku ubin otomatis RPG Maker VX Ace (47 ubin) saya mulai melakukan sesuatu seperti ini:

(kiri 0 atau 1) + (kanan 0 atau 1) + (naik 0 atau 1) + (turun 0 atau 1) sekarang saya punya 5 kasing.

jika 4 = Ubin 46 ditempatkan

jika 3 asrama =

jika 2 4 kasus + 2 kasus tidak yakin tentang algoritma tetapi tidak banyak cabang yang harus dibuat.

jika 1 = mengerjakannya tetapi setiap arah bisa berakhir dalam 4 kasus

jika 0 = saya dapat menggunakan algoritma angka yang ditunjukkan dalam tautan dengan 1, 2, 4, 8 dan mendapatkan id dari 1 hingga 15 saya dapat langsung menggunakan.

Saya bukan seorang programmer dan bukan yang terbaik dengan algoritma matematika dan solusi 1, 2, 4, 8, 16, 32, 64, 128 Saya juga tidak terlalu suka.

Mungkin pendekatan saya setidaknya lebih baik dari itu.

Haji
sumber
1
Saya tidak yakin jawaban ini sepenuhnya menjawab pertanyaan, dapatkah Anda menjelaskan lebih banyak? Jika Anda merujuk ke sesuatu yang lain, bisakah Anda setidaknya menghubungkannya?
Vaillancourt