Aller au contenu principal

Session 113 — Phase 2.C : tirs joueur tuent les aliens

Contexte

Les phases 2.A (machine a etats IA pure + 17 tests) et 2.B (integration
runtime via AlienControlSystem + AiWorldAdapter + 7 tests d’integration)
etaient livrees, mais les aliens etaient invincibles : aucun tir joueur ne
leur infligeait de degats. Cette phase 2.C ferme la boucle visuelle : on tire,
l’alien encaisse, transition TAKE_DAMAGE ou RESPONSE (75/25), et meurt
quand HP ≤ 0 avec animation de fade.

Architecture du wiring

 GameAppState.setupPhysics()
   ...
   +-- AlienControlSystem (deja la, phase 2.B)
   |
   +-- AlienHitDetector (NEW)
        |
        +-- branche sur BulletUpdateSystem.setAlienHitDetector()
        |    -> projectiles : Plasma, Blaster, Rocket, Grenade, Mine, Lazer...
        |
        +-- branche sur HitscanTracerSystem.setAlienHitDetector()
             -> hitscan    : Shotgun, Machine Gun, MindZap

Un meme AlienHitDetector est injecte dans les deux systemes de tir : il
lit la liste d’aliens vivants depuis l’AlienControlSystem et expose deux
methodes :

  • findHitByPoint(jx, jy, jz) : test point-vs-capsule pour les projectiles
    (chaque frame, apres update de la position)
  • findHitByRay(from, dir, maxDist) : test ray-vs-capsule (intersection
    cylindre XZ + check Y) pour les hitscan, retourne aussi la distance pour
    comparer avec l’impact mur et prendre le plus proche

Modele de capsule

Chaque alien est modelise comme une capsule verticale :
Centre XZ = position monde Amiga / 32 (avec flip Z)
Centre Y = node.getLocalTranslation().y (= spawnY courant)
Rayon = 0.5 unite JME (~ 16 unites Amiga)
Demi-hauteur = 0.9 unite JME (~ 1m80 ingame)

Note : on n’utilise PAS AlienDef.collisionRadius() (= 80/160/320 Amiga)
qui est specifique a la collision murs (pour empecher les aliens de se
coincer dans les coins). Pour le hit testing on prend une capsule plus serree
autour du sprite.

Math du raycast vs capsule

Polynome quadratique en t pour le cylindre XZ :

  |O.xz + t*D.xz - C.xz|^2 = r^2
  a = Dx^2 + Dz^2
  b = 2 * ((Ox-Cx)*Dx + (Oz-Cz)*Dz)
  c = (Ox-Cx)^2 + (Oz-Cz)^2 - r^2

On prend la plus petite racine positive, puis on verifie que Oy + t*Dy est
dans [Cy - halfHeight, Cy + halfHeight]. Pour plusieurs aliens, on garde
le t minimum.

Routing damage

Les deux systemes utilisent la meme chaine d’application :

 hit detecte
   -> AlienHitDetector.applyDamage(alien, damage)
   -> AlienAI.inflictDamage(alien, damage)
   -> alien.damageTaken += damage
   -> au prochain AlienAI.update() :
      applyDamage() consomme damageTaken, decremente HP, applique 75/25

Le damage vient de BulletDef.hitDamage() qui est lu du GLF.
– Plasma Bolt = 1 HP
– Shotgun Round = 1 HP par bille (count=2 = 2 HP par tir)
– Rocket = ~5 HP
– MindZap = ~10 HP

Donc Red Alien (HP=2) meurt en 2 tirs Plasma ou en 1 tir Shotgun bien place.
Mantis Boss (HP=125) prend ~125 plasmas. C’est fidele au jeu original.

Fichiers nouveaux

  1. combat/AlienHitDetector.java : detecteur point/ray vs aliens
    (~210 lignes). API publique :
    AlienHit findHitByRay(from, dir, maxDist) retourne record AlienHit(alien, impact, distance)
    AlienRuntimeState findHitByPoint(x, y, z)
    applyDamage(alien, amount) (delegate vers AlienAI.inflictDamage)

  2. test/.../AlienHitDetectorTest.java : 11 tests JUnit qui valident
    – Hit au centre, hit dans le rayon, miss hors rayon, miss trop haut
    – Alien mort = pas touchable
    – Ray traverse le centre, ray rate, ray trop court, ray vertical pur
    – Plusieurs aliens : on touche le plus proche
    – applyDamage accumule dans damageTaken

Fichiers modifies

  1. combat/BulletUpdateSystem.java : ajout du test point-vs-aliens
    apres update position, AVANT le test mur (l’alien doit prevaler sur le
    mur derriere lui). Setter setAlienHitDetector().

  2. combat/HitscanTracerSystem.java :
    – Setter setAlienHitDetector()
    spawnTracer() prend maintenant un parametre damage
    – Le tracer choisit la cible la plus proche entre alien et mur
    – Si on touche un alien : applyDamage puis tracer s’arrete sur l’alien
    – Surcharge legacy spawnTracer(origin, dir, type) deprecated pour la
    retro-compat (= 0 damage)

  3. combat/PlayerShootSystem.java :
    fireHitscan() prend maintenant le BulletDef bullet en parametre
    – Lit bullet.hitDamage() et le passe au tracer

  4. app/GameAppState.java : creation de l’AlienHitDetector apres
    l’AlienControlSystem dans setupPhysics(), branche sur
    bulletUpdateSystem et tracerSystem via les setters.

Tests

Total session 113 : 35 tests = 17 unitaires AlienAI + 7 integration
AlienDefLoader + 11 unitaires AlienHitDetector.

./gradlew test

Resultat in-game attendu

Sur le niveau A :
1. Les Red Aliens spawnent et patrouillent en mode DEFAULT (anim 0).
2. Quand on entre dans leur LOS, transition RESPONSE (anim 1) au bout de
5 frames Amiga (= 0.1 sec, reactionTime du Red Alien).
3. Ils chargent vers le joueur en ligne droite.
4. Tirer dessus : la bullet/le tracer s’arrete sur l’alien, on voit le
flash d’impact. 75% du temps, l’alien aggro (passe directement en
RESPONSE meme s’il etait en DEFAULT). 25% du temps, il anime un « hit »
(mode TAKE_DAMAGE, anim 2) pendant ~8 frames avant de revenir en DEFAULT.
5. Au 2e plasma (HP=2), il meurt : mode DIE, anim 3, fade pendant 25 frames
(~0.5 sec) puis le sprite est detache.

Boss vector (Mantis, Snake, Wasp, Crab) : meme principe mais HP=125,
donc il faut beaucoup de tirs pour les tomber. Capsule = 0.5 JME de rayon
ce qui peut paraitre etroit pour ces gros boss ; on peut ajuster en 2.D si
necessaire (utiliser def.girth() pour adapter le rayon de la capsule).

Limitations connues (a faire en phase 2.D)

  • Capsule rigide : pas de bias d’auto-aim Y. L’ASM autorise une tolerance
    pour les tirs un peu hauts/bas. Pour l’instant la capsule est rigide a
    ±0.9 unite JME.
  • Splash damage : Rocket/Grenade explosent mais n’infligent que des
    degats directs. Le rayon d’explosion (BulletDef.explosiveForce) n’est
    pas applique aux aliens dans le rayon.
  • Bullets PHYSICS (grenades) : les bullets gerees par PhysicsBulletSystem
    ne testent PAS encore les aliens (elles sont a part dans la boucle). On
    pourra brancher en 2.D si necessaire.
  • Rayon de capsule fixe : on ne lit pas def.girth() pour ajuster, donc
    les boss girth=2 (320 Amiga = 10 JME) sont touches comme des aliens
    normaux (rayon 0.5). Visuellement c’est etroit pour Mantis (height=800).
  • Aliens armes ne tirent toujours pas sur le joueur : reste un TODO
    dans AlienAI.doResponse() quand def.attacksWithGun()=true.
  • Pas de ricochet alien : si une bullet rate l’alien et continue vers le
    mur, c’est OK (test mur applique apres). Mais une bullet qui touche un
    alien explose dessus, sans degats AOE possibles sur les aliens voisins.

Statistiques cumulees session 113 (3 phases)

  • 8 fichiers nouveaux : 6 dans core/ai/ + 1 dans world/ + 1 dans combat/
  • 6 fichiers modifies : tools/LnkParser, tools/LevelJsonExporter,
    combat/BulletUpdateSystem, combat/HitscanTracerSystem, combat/PlayerShootSystem,
    app/GameAppState, world/AlienControlSystem (cree en 2.B)
  • 3 fichiers test : AlienAITest, AlienDefLoaderIntegrationTest, AlienHitDetectorTest
  • 35 tests au total
  • Build modifie : build.gradle (deps JUnit 5), gradle.properties (action 34=test)

Laisser un commentaire

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