Aller au contenu principal

Session 121 — Animations alien correctes + collision joueur-alien

Problèmes signalés

  1. Anims incorrectes : sur test_alien_bullets, le Red Alien affiche la
    frame d’explosion au moment d’attaquer, au lieu de la vraie frame
    d’attaque. La fix de session 120 (idleFrame) ne règle que la frame
    de repos, pas les animations dynamiques (marche, attaque, hit, mort).

  2. Joueur traverse les aliens : pas de collision physique
    joueur ↔ alien, le joueur peut marcher à travers eux ou les escalader.

Analyse du bug d’animation

Après lecture de hires.s::JUMPALIENANIM (ligne 6050+) et
newaliencontrol.s :

Le ASM lit EntT_WhichAnim_b(a0) qui vaut :
– 0 = walking
– 1 = attacking
– 2 = getting hit
– 3 = dying

Cette valeur est traduite en option index dans la table d’anim de
l’alien :
– 0/2/4/6 = walk selon viewpoint (TOWARDS / RIGHT / AWAY / LEFT)
– 8 = attaque
– 9 = hit
– 10 = mort

L’ASM va ensuite chercher la frame courante dans cette option, et lit le
byte 0 (= wadFrame) pour savoir quelle frame du WAD afficher.

Notre code Java avant cette session faisait l’inverse : il assumait des
frames fixes (ATTACK_FRAME_BASE = 16, HIT = 17, DIE = 18) indépendamment
de l’alien. Pour Red Alien dont l’option 8 (attack) pointe peut-être vers
les frames 5-9, on affichait la frame 16 = explosion. D’où le bug.

Modifications

Niveaux de test individuels

TestLevelGenerator.java : ajout de generate_singleAlien(type) qui
génère un niveau par alien combatif (16 fichiers test_alien_*.json).
Permet d’isoler un alien pour observation.

./gradlew run --args="--test-level ALIEN_RED_ALIEN"
./gradlew run --args="--test-level ALIEN_GUARD"
./gradlew run --args="--test-level ALIEN_MANTIS_BOSS"
# etc. pour chacun des 16 aliens combatifs

Anims correctes

Nouveau fichier AlienAnimsResolver.java dans core/ai/ :

  • Charge la section alienAnims[] depuis definitions.json (exportée en
    session 120 par LevelJsonExporter)
  • Expose optionForMode(mode, viewpoint) qui mappe l’état IA → index option
    (0/2/4/6 walk, 8 attack, 9 hit, 10 die)
  • Expose frameIndexInOption(alien, opt, phase, ticks) qui calcule la
    frame courante dans l’option avec auto-loop à la fin (équivalent
    ASM tst.b (a6,d3.w); bge .noendanim)
  • Si la table est absente (vieux definitions.json), retourne un resolver
    vide qui déclenche le fallback sur la convention historique

AlienSpriteController.java : refonte complète.

  • Reçoit maintenant alienDefIndex et AlienAnimsResolver au constructeur
  • update() :
  • Si la vraie table est chargée → utilise optionForMode() +
    frameAt(alienIdx, opt, frameInOpt).wadFrame()
  • Sinon → fallback sur AlienAnimTable.pickFrame() (ancien comportement)
  • Tics par frame : 8 pour walk, 5 pour les actions (attaque/hit/mort plus
    rapides)
  • Fallback : si une option pointée est vide pour cet alien (= padding
    binaire), retombe sur option 0 pour avoir au moins quelque chose à
    afficher

AlienControlSystem.java : charge le resolver une fois à l’init et
le passe à chaque sprite controller. Logue si la table est chargée ou si
on est en mode fallback.

Collision joueur-alien

GameAppState.java : nouvelle méthode applyAlienCollision() appelée
chaque frame après applyZoneLogic().

  • Pour chaque alien vivant : calcule la distance horizontale au joueur
  • Si dist < PLAYER_RADIUS + ALIEN_RADIUS_JME (0.35 + 0.6 = 0.95 JME) :
    pousse le joueur radialement à la distance limite
  • Test purement horizontal (X/Z), Y ignoré pour ne pas casser saut/lift
  • Équivalent ASM : Plr1_CheckObjectCollide dans newaliencontrol.s

Rayon alien fixé à 0.6 JME pour V1. Plus tard, lire AlienDef.collisionRadius()
(= 80/160/320 Amiga selon girth) pour avoir un radius par alien.

Pipeline

# Si on n'a pas encore les anims dans definitions.json :
./gradlew convertLevels    # regénère definitions.json avec alienAnims[]

./gradlew genTestLevels    # produit les test_alien_*.json individuels
./gradlew buildScenes      # produit les scene_TEST_ALIEN_*.j3o

# Test d'ensemble :
./gradlew run --args="--test-level ALIEN_BULLETS"

# Test isolé par alien :
./gradlew run --args="--test-level ALIEN_RED_ALIEN"
./gradlew run --args="--test-level ALIEN_ASHNARG"
# etc.

Résultat attendu

  • Red Alien attaquant doit afficher la vraie animation d’attaque (pas
    l’explosion)
  • Chaque alien doit avoir ses 4 frames de marche correctes selon son orientation
  • Le joueur ne peut plus traverser les aliens : il est repoussé à ~1 unité
    JME de chaque alien vivant

Limitations connues

  • Le viewpoint dans le ASM original utilise option 0/2/4/6, mais en
    pratique JUMPALIENANIM ASM pour les aliens NPC fait moveq #0,d0
    (= toujours option 0). À surveiller : si les aliens semblent ne pas
    changer quand on tourne autour d’eux, simplifier en option 0 pour walk.
  • Le rayon alien est fixe (pas par girth)
  • Le flipMirror est lu mais pas appliqué visuellement
    (le sprite n’est pas mirroré). Mineur, peut donner des aliens « décalqués »
    symétriquement, mais pas critique pour l’identification.
  • Le doActionFlag (trigger de tir/hit) n’est pas encore branché sur
    l’IA : celle-ci utilise toujours FIRE_FRAME = 4 hardcodé dans
    AlienAI. À raffiner dans une prochaine session pour avoir le timing
    de tir exact par alien.

Laisser un commentaire

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