Aller au contenu principal

Session 101 — Fusion ZDoorWalls par edge (effet bloc plein)

Symptôme

Après les fixes session 100, les portes présentaient encore un effet visuel
incorrect : le panneau chevron jaune/noir apparaissait découpé horizontalement
avec une bande noire au milieu (visible sur captures du joueur). La texture ne
glissait pas comme un bloc unique, et les morceaux haut/bas étaient séparés
par un gap où on voyait l’arrière-plan noir.

Diagnostic

Le bug venait de la phase de build (LevelSceneBuilder), pas du runtime.

Pour une porte donnée, le binaire définit souvent plusieurs ZDoorWalls sur
le MEME edge XZ
mais à des hauteurs verticales différentes. Typiquement :
– un panneau de porte (par exemple yBot=-10, yTop=-2)
– un linteau décoratif (par exemple yBot=0, yTop=2)
– un wall de transition entre les deux (souvent invisible ou avec une autre
texture, mais qui crée un gap dans la géométrie ZDoorWall)

Mon code rendait chaque ZDoorWall comme un quad indépendant, ce qui :
– crée une discontinuité verticale entre les segments (bande noire visible)
– désynchronise l’effet de glissement (chaque seg anime sa propre hauteur)
– détruit l’illusion d’un « bloc plein » qui monte

L’ASM 2.5D ne montrait pas ce problème parce que tous les ZDoorWalls étaient
rasterisés dans la même passe scanline : visuellement les pixels étaient
contigus même si la structure interne était fragmentée.

Fix (LevelSceneBuilder.buildScene)

Avant : un Geometry par ZDoorWall :

for (float[] seg : acc.segs) {
    Geometry sg = makeDoorSegGeo(..., segYTop, segYBot, ...);
    dn.attachChild(sg);
}

Après : grouper les segs par position XZ, fusionner verticalement :

Map<String, List<float[]>> bySpan = ...;  // clé = "x0_z0_x1_z1"
for (float[] seg : acc.segs)
    bySpan.computeIfAbsent(spanKey(seg), k -> new ArrayList<>()).add(seg);

for (var group : bySpan.values()) {
    float[] anchor = ...;          // seg avec le yBot le plus bas
    float groupYBot = min(yBots);  // bas global du groupe
    float groupYTop = max(yTops);  // haut global du groupe
    Geometry sg = makeDoorSegGeo(..., groupYTop, groupYBot, ...);
    dn.attachChild(sg);
}

La texture/UV/yOffset proviennent du seg-ancre (yBot le plus bas), car son
yOffset est calibré pour ce yBot — les UV restent alignées au sol original.

Résultat attendu

  • Plus de bande noire au milieu du panneau
  • Glissement uniforme de la texture vers le haut quand la porte s’ouvre
  • Effet « bloc plein qui se rétracte dans le plafond » comme dans le jeu original
  • L’ouverture continue de laisser voir l’autre côté du couloir (porte mince,
    pas de back face requise)

Pour tester

Important : ce fix change la géométrie des .j3o, donc :

./gradlew buildScenes run

(pas juste run comme pour les fixes session 100)

Zones à vérifier en priorité :
– Porte zone 5 (entrée level A, chevron) — plus de discontinuité verticale
– Porte zone 30 (6 walls) — le test stress, le plus susceptible d’avoir des
segs disjoints
– Porte zone 132 (rouge, large) — confirm que le rendu reste propre sur les
grandes portes

Fichiers modifiés

  • tools/LevelSceneBuilder.java : refonte de la boucle de création des
    Geometry porte (~30 lignes), grouping par clé XZ avec LinkedHashMap,
    fusion vertical (min/max sur yBot/yTop du groupe).

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *