Autotiling elegante


10

Estoy buscando información sobre cómo las personas implementan el autotiling en sus juegos basados ​​en mosaicos. Hasta ahora, siempre lo he improvisado con un montón de declaraciones "si ... más ..." codificadas, y ahora decidí que es hora de encontrar una solución más elegante. Busqué en Internet ejemplos de implementaciones de autotiling y debates sobre el tema, pero solo encontré tres artículos:

(Especialmente el último es completo y muy útil).

También he examinado varias implementaciones y documentación de bibliotecas, que lo implementan, por ejemplo, flixel: http://www.flixel.org/features.html#tilemaps

Lamentablemente, todas las soluciones que pude encontrar son exactamente tan improvisadas y desordenadas como lo que comencé, y casi nunca cubren todos los casos posibles.

Estoy buscando un ejemplo elegante de implementación de autotiling del que pueda aprender.

Respuestas:



3

Llegué aquí buscando en Google este problema, leí los artículos vinculados y produje una solución relativamente compacta que genera el conjunto común de 47 mosaicos. Requiere un conjunto de fichas 2x3 para el material autotiled de esta manera:un juego de fichas de autotile 2x3

Con una variante de un solo mosaico en la parte superior izquierda, esquinas interiores en la parte superior derecha y cuatro mosaicos de esquinas exteriores en la parte inferior (puede reconocer esta disposición de RPG Maker).

El truco consiste en dividir cada mosaico de mapa "lógico" en 4 medios mosaicos para renderizar. además, un medio mosaico en el conjunto de mosaicos solo puede estar en esa posición en un mosaico generado, por lo que un medio mosaico superior izquierdo solo se puede usar en una posición superior izquierda.

Estas restricciones significan que solo necesita verificar 3 vecinos de mosaico completo por medio mosaico, en lugar de los 8 mosaicos vecinos.

Implementé esta idea rápidamente para probarla. Aquí está el código de prueba de concepto (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;
}    

Explicación:

  • Aes la parte superior izquierda del mosaico, Bes la parte superior derecha, Ces la parte inferior izquierda, Des la parte inferior derecha.
  • edges contiene máscaras de bits para cada uno de estos, por lo que solo podemos obtener la información de vecino relevante.
  • map* son diccionarios que asignan estados vecinos a índices gráficos en la imagen del conjunto de mosaicos (0..24).
    • Como cada mitad de mosaico verifica 3 vecinos, cada uno tiene 2 ^ 3 = 8 estados.
  • _tile es el mosaico destinado al autotiling.
  • Dado que nuestros mosaicos lógicos son dos veces más grandes que nuestros mosaicos de representación, todas las coordenadas automáticas (x, y) deben duplicarse en el mapa de representación.

De todos modos, aquí están los resultados (con solo un mosaico, de todos modos):ingrese la descripción de la imagen aquí


0

Leí la mayoría de los enlaces y pasé algún tiempo para encontrar otra solución. No sé si es bueno o no, pero para simular el comportamiento del mosaico automático RPG Maker VX Ace (47 mosaicos) comencé a hacer algo como esto:

(izquierda 0 o 1) + (derecha 0 o 1) + (arriba 0 o 1) + (abajo 0 o 1) ahora tengo 5 casos.

si 4 = se coloca el mosaico 46

si 3 huéspedes =

if 2 4 casos + 2 casos no estoy seguro sobre el algoritmo pero no hay muchas ramas para hacer.

si 1 = trabajando en él pero cada dirección puede terminar en 4 casos

si 0 = puedo usar el algoritmo numérico que se muestra en los enlaces con 1, 2, 4, 8 y obtener una identificación del 1 al 15, puedo usarlo directamente.

No soy un programador y no soy el mejor con algoritmos matemáticos y la solución 1, 2, 4, 8, 16, 32, 64, 128 que tampoco me gustó mucho.

Quizás mi enfoque es al menos mejor que eso.


1
No estoy seguro de que esta respuesta responda completamente a la pregunta, ¿podría explicar un poco más? Si se refiere a otra cosa, ¿podría al menos vincularla?
Vaillancourt
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.