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
-
combat/AlienHitDetector.java: detecteur point/ray vs aliens
(~210 lignes). API publique :
–AlienHit findHitByRay(from, dir, maxDist)retournerecord AlienHit(alien, impact, distance)
–AlienRuntimeState findHitByPoint(x, y, z)
–applyDamage(alien, amount)(delegate versAlienAI.inflictDamage) -
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 dansdamageTaken
Fichiers modifies
-
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). SettersetAlienHitDetector(). -
combat/HitscanTracerSystem.java:
– SettersetAlienHitDetector()
–spawnTracer()prend maintenant un parametredamage
– Le tracer choisit la cible la plus proche entre alien et mur
– Si on touche un alien :applyDamagepuis tracer s’arrete sur l’alien
– Surcharge legacyspawnTracer(origin, dir, type)deprecated pour la
retro-compat (= 0 damage) -
combat/PlayerShootSystem.java:
–fireHitscan()prend maintenant leBulletDef bulleten parametre
– Litbullet.hitDamage()et le passe au tracer -
app/GameAppState.java: creation de l’AlienHitDetectorapres
l’AlienControlSystemdanssetupPhysics(), branche sur
bulletUpdateSystemettracerSystemvia 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 bossgirth=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
dansAlienAI.doResponse()quanddef.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 dansworld/+ 1 danscombat/ - 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)