Элегантный автотайлинг

10

Я ищу информацию о том, как люди внедряют автотиллинг в своих играх на основе тайлов. До сих пор я всегда импровизировал с кучей жестко закодированных выражений «если ... еще ...», и теперь я решил, что пришло время найти более элегантное решение. Я отправился на поиски в интернете примеров реализации автотайлинга и обсуждений по этой теме, но я придумал только три статьи:

(Особенно последний является всеобъемлющим и очень полезным.)

Я также рассмотрел различные реализации и документацию библиотек, которые ее реализуют, например, flixel: http://www.flixel.org/features.html#tilemaps

К сожалению, все решения, которые я мог найти, были такими же импровизированными и случайными, как и то, с чего я начинал, и почти никогда не покрывали все возможные случаи.

Я ищу элегантный пример реализации автотайлинга, из которого я мог бы поучиться.

Радомир Доперальский
источник

Ответы:

10

Я использовал Побитовый метод для применения TileMap и нашел его очень элегантным решением. В статье приводится конкретный пример и обсуждается, как расширить алгоритм для обработки нескольких типов местности.

NoobsArePeople2
источник
Это похоже на алгоритм, используемый flixel "AUTO" в режиме автотиллинга. Спасибо, я добавляю его в свой список.
Радомир Допьеральский
3

Я сам прибыл сюда, погуглив эту проблему, прочитав соответствующие статьи, и создал относительно компактное решение, которое генерирует общий набор из 47 плиток. Требуется набор тайлов 2x3 для материала с автонастройкой, подобного этому:2x3 автоматическая плитка

С вариантом с одной плиткой в ​​верхнем левом углу, внутренними углами в верхнем правом углу и четырьмя внешними угловыми плитками в нижней части (вы можете узнать это расположение в 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 является плиткой, предназначенной для автотиллинга.
  • Поскольку наши логические плитки в два раза больше наших плиток рендеринга, все координаты autotile (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, который я могу использовать напрямую.

Я не программист и не лучший с математическими алгоритмами и решениями 1, 2, 4, 8, 16, 32, 64, 128, которые мне тоже не очень понравились.

Может быть, мой подход, по крайней мере, лучше, чем это.

Hajami
источник
1
Я не уверен, что этот ответ полностью отвечает на вопрос, не могли бы вы объяснить немного больше? Если вы ссылаетесь на что-то еще, можете ли вы хотя бы сослаться на это?
Vaillancourt