Sono arrivato qui cercando su Google questo problema, ho letto gli articoli collegati e prodotto una soluzione relativamente compatta che genera il set comune di 47 tessere. Richiede un set di tessere 2x3 per il materiale autotiledato in questo modo:
Con una variante a tessera singola in alto a sinistra, angoli interni in alto a destra e quattro tessere angolari esterne in basso (puoi riconoscere questa disposizione da RPG Maker).
Il trucco è quello di spezzare ogni tessera "logica" in 4 semi-tessere per il rendering. inoltre, una mezza tessera nel set di tessere può trovarsi solo in quella posizione in una tessera generata, quindi una mezza tessera in alto a sinistra può essere utilizzata solo in una posizione in alto a sinistra.
Queste restrizioni indicano che è necessario controllare solo 3 vicini a tessera intera per mezza tessera, anziché tutte e 8 le tessere vicine.
Ho implementato rapidamente questa idea per testarla. Ecco il codice di prova (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;
}
Spiegazione:
A
è la parte in alto a sinistra della tessera, B
è in alto a destra, C
è in basso a sinistra, D
è in basso a destra.
edges
contiene maschere di bit per ognuna di queste, quindi possiamo prendere solo le informazioni relative al vicino.
map*
sono dizionari che mappano gli stati vicini agli indici grafici nell'immagine tileset (0..24).
- poiché ogni mezza tessera controlla 3 vicini, ognuno ha 2 ^ 3 = 8 stati.
_tile
è la tessera scelta come target per l'autotiling.
- Poiché le nostre tessere logiche sono due volte più grandi delle nostre tessere di rendering, tutti i coordini di autotile (x, y) devono essere raddoppiati nella mappa di rendering.
Ad ogni modo, ecco i risultati (con una sola tessera, comunque):