Przyszedłem tutaj, googling sam problem, przeczytałem powiązane artykuły i stworzyłem stosunkowo kompaktowe rozwiązanie, które generuje wspólny zestaw 47 płytek. Wymaga zestawu kafelków 2x3 dla autotilowanego materiału, takiego jak ten:
Z wariantem z pojedynczą płytką w lewym górnym rogu, wewnętrznymi narożnikami w prawym górnym rogu i czterema zewnętrznymi płytkami w rogu na dole (możesz rozpoznać ten układ w RPG Maker).
Sztuką jest podzielenie każdego „logicznego” kafelka mapy na 4 półpłytki do renderowania. ponadto półpłytka w zestawie klocków może znajdować się tylko w tej pozycji w wygenerowanym kafelku, więc lewy górny pół-kafelek może być użyty tylko w lewym górnym rogu.
Ograniczenia te oznaczają, że musisz sprawdzić tylko 3 sąsiadów z pełnymi kafelkami na pół kafelka, zamiast wszystkich 8 sąsiadujących kafelków.
Szybko wdrożyłem ten pomysł, aby go przetestować. Oto kod 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;
}
Wyjaśnienie:
A
to górna lewa część kafelka, B
prawy górny róg, C
lewy D
dolny róg, prawy dolny róg.
edges
przechowuje maski bitów dla każdego z nich, dzięki czemu możemy pobrać tylko odpowiednie informacje o sąsiadach.
map*
to słowniki odwzorowujące stany sąsiednie na wskaźniki graficzne w obrazie zestawu klocków (0..24).
- ponieważ każdy półpłytek sprawdza 3 sąsiadów, każdy ma 2 ^ 3 = 8 stanów.
_tile
to kafelek przeznaczony do autotilowania.
- Ponieważ nasze logiczne kafelki są dwa razy większe niż nasze kafelki renderujące, wszystkie współrzędne autotile (x, y) muszą zostać podwojone na mapie renderowania.
Tak czy inaczej, oto wyniki (w każdym razie tylko z jednym kafelkiem):