Je suis arrivé ici en recherchant moi-même ce problème sur Google, en lisant les articles liés et en produisant une solution relativement compacte qui génère l'ensemble commun de 47 tuiles. Il nécessite un jeu de tuiles 2x3 pour le matériau autotiled comme ceci:
Avec une variante à une seule tuile en haut à gauche, des coins intérieurs en haut à droite et quatre tuiles de coin extérieur en bas (vous pouvez reconnaître cet arrangement de RPG Maker).
L'astuce consiste à diviser chaque tuile de carte "logique" en 4 demi-tuiles pour le rendu. en outre, une demi-tuile dans le jeu de tuiles ne peut être dans cette position que dans une tuile générée, donc une demi-tuile en haut à gauche ne peut être utilisée que dans une position en haut à gauche.
Ces restrictions signifient que vous n'avez besoin de cocher que 3 voisins de tuiles complètes par demi-tuile, au lieu des 8 tuiles voisines.
J'ai rapidement mis en œuvre cette idée pour la tester. Voici le code de preuve de 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;
}
Explication:
A
est la partie supérieure gauche de la tuile, B
est en haut à droite, C
est en bas à gauche, D
est en bas à droite.
edges
contient des bitmasks pour chacun d'entre eux, nous pouvons donc saisir uniquement les informations de voisinage pertinentes.
map*
sont des dictionnaires mappant les états voisins aux index graphiques dans l'image de jeu de tuiles (0..24).
- puisque chaque demi-tuile vérifie 3 voisins, chacun a 2 ^ 3 = 8 états.
_tile
est la tuile ciblée pour le tuilage automatique.
- Puisque nos tuiles logiques sont deux fois plus grandes que nos tuiles de rendu, tous les cordons d'autotile (x, y) doivent être doublés dans la carte de rendu.
Quoi qu'il en soit, voici les résultats (avec une seule tuile, de toute façon):