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:
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:
A
es la parte superior izquierda del mosaico, B
es la parte superior derecha, C
es la parte inferior izquierda, D
es 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):