From f1f79ed76564b4989cba3f6c5ee035103fa44781 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 7 Mar 2026 23:50:07 +0000 Subject: [PATCH] fix: correct dirt autotile direction and simplify edge logic Dirt tiles (dirt-on-transparent) must be applied to DIRT tiles checking for non-dirt neighbors, not to GRASS tiles. The previous approach had dirt edges facing the wrong direction because the dirt island's edges point inward from the center, not outward from the grass. Water edges (watergrass = grass-on-water) remain applied to GRASS tiles since the grass portion aligns correctly with the base grass layer. Co-Authored-By: Claude Opus 4.6 --- client/src/scenes/GameScene.ts | 85 +++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/client/src/scenes/GameScene.ts b/client/src/scenes/GameScene.ts index 3de3ea5..66cfeab 100644 --- a/client/src/scenes/GameScene.ts +++ b/client/src/scenes/GameScene.ts @@ -163,34 +163,59 @@ export class GameScene extends Phaser.Scene { return terrain[y * worldWidth + x]; }; - // For a GRASS tile, pick the watergrass/dirt transition tile based on - // which neighbors are the "other" terrain type. - // The LPC edge tiles are drawn FROM the grass perspective (grass is the terrain, - // water/dirt is the background bleeding through at edges). - const pickEdgeTile = (x: number, y: number, otherTerrain: number): number => { - const isOther = (dx: number, dy: number) => getTerr(x + dx, y + dy) === otherTerrain; - const n = isOther(0, -1), s = isOther(0, 1), w = isOther(-1, 0), e = isOther(1, 0); - const nw = isOther(-1, -1), ne = isOther(1, -1), sw = isOther(-1, 1), se = isOther(1, 1); + // Pick autotile for a GRASS tile in the watergrass layer. + // watergrass.png = grass-on-water: edge tiles show grass with water bleeding through. + // Applied to GRASS tiles, checking which neighbors are WATER. + const pickWaterEdge = (x: number, y: number): number => { + const isW = (dx: number, dy: number) => getTerr(x + dx, y + dy) === Terrain.WATER; + const n = isW(0, -1), s = isW(0, 1), w = isW(-1, 0), e = isW(1, 0); + const nw = isW(-1, -1), ne = isW(1, -1), sw = isW(-1, 1), se = isW(1, 1); - // Outer corners (two cardinal sides are the other terrain) - if (n && w) return 6; // outer-NW: grass only in SE, other terrain in NW - if (n && e) return 8; // outer-NE - if (s && w) return 12; // outer-SW - if (s && e) return 14; // outer-SE - // Edges (one cardinal side is the other terrain) - if (n) return 7; // N-edge: other terrain bleeds from north - if (s) return 13; // S-edge - if (w) return 9; // W-edge - if (e) return 11; // E-edge - // Inner corners (all cardinal = grass, but a diagonal is the other terrain) - if (se) return 0; // inner-SE: other terrain peeks in SE corner - if (sw) return 1; // inner-SW - if (ne) return 3; // inner-NE - if (nw) return 4; // inner-NW - // No adjacent other-terrain at all + // Outer corners (two cardinal sides are water) + if (n && w) return 6; + if (n && e) return 8; + if (s && w) return 12; + if (s && e) return 14; + // Edges (one cardinal side is water) + if (n) return 7; + if (s) return 13; + if (w) return 9; + if (e) return 11; + // Inner corners (diagonal-only water) — small water notch in grass + if (se) return 0; + if (sw) return 1; + if (ne) return 3; + if (nw) return 4; return -1; }; + // Pick autotile for a DIRT tile in the dirt layer. + // dirt.png = dirt-on-transparent: edge tiles show dirt with transparent edges. + // Applied to DIRT tiles, checking which neighbors are NOT dirt. + const pickDirtEdge = (x: number, y: number): number => { + const notDirt = (dx: number, dy: number) => getTerr(x + dx, y + dy) !== Terrain.DIRT; + const n = notDirt(0, -1), s = notDirt(0, 1), w = notDirt(-1, 0), e = notDirt(1, 0); + const nw = notDirt(-1, -1), ne = notDirt(1, -1), sw = notDirt(-1, 1), se = notDirt(1, 1); + + // Outer corners (two sides are not-dirt → this dirt tile is at a corner of the dirt body) + if (n && w) return 6; + if (n && e) return 8; + if (s && w) return 12; + if (s && e) return 14; + // Edges + if (n) return 7; + if (s) return 13; + if (w) return 9; + if (e) return 11; + // Inner corners (diagonal-only grass → small transparent notch in dirt) + if (se) return 0; + if (sw) return 1; + if (ne) return 3; + if (nw) return 4; + // Fully surrounded by dirt + return FILL; + }; + // Build tile data arrays for each layer const grassData: number[][] = []; // base: solid grass everywhere const waterData: number[][] = []; // watergrass transitions + solid water @@ -209,20 +234,18 @@ export class GameScene extends Phaser.Scene { // Base: always solid grass grassRow.push(FILL); - // Water layer + // Water layer: watergrass edges on GRASS tiles, solid fill on WATER tiles if (t === Terrain.WATER) { - waterRow.push(FILL); // solid water + waterRow.push(FILL); } else if (t === Terrain.GRASS) { - waterRow.push(pickEdgeTile(x, y, Terrain.WATER)); + waterRow.push(pickWaterEdge(x, y)); } else { waterRow.push(-1); } - // Dirt layer + // Dirt layer: dirt edges on DIRT tiles (checking for non-dirt neighbors) if (t === Terrain.DIRT) { - dirtRow.push(FILL); // solid dirt - } else if (t === Terrain.GRASS) { - dirtRow.push(pickEdgeTile(x, y, Terrain.DIRT)); + dirtRow.push(pickDirtEdge(x, y)); } else { dirtRow.push(-1); }