Fase 6d: migrar Enemy al sistema de fisica vectorial

Segunda entidad migrada. Los enemigos (Pentagon, Quadrat, Molinillo)
ahora viven en el PhysicsWorld con velocidad vectorial. Las colisiones
entre enemigos quedan habilitadas automaticamente (novedad: antes no
se chocaban).

Cambios en enemy.hpp:
- Eliminado: float velocity_ (escalar)
- Eliminado: void mou() (lo hace el world)
- Anadido: override postUpdate()
- Anadido: helper privado setVelocityFromAngle(angle, speed)
- Anadido: direction_change_timer_ para zigzag periodico del Pentagon

Cambios en enemy.cpp:
- Constructor configura body_ (mass=5 default, radius=0 inactivo,
  restitution=1.0 elastico, sin damping)
- init() ajusta masa por tipo:
  * Pentagon: 5.0 (esquivador ligero)
  * Quadrat: 8.0 (tanque pesado)
  * Molinillo: 4.0 (agil rapido)
- init() setea body_.radius = ENEMY_RADIUS al spawn
- behaviorPentagon: zigzag por probabilidad temporal (0.8/s) en lugar
  de detectar paredes; el rebote contra muros lo hace PhysicsWorld
- behaviorQuadrat: tracking discreto cada TRACKING_INTERVAL — mezcla
  velocity actual con direccion al ship (LERP por tracking_strength)
- behaviorMolinillo: solo boost de rotacion visual cerca del ship;
  movimiento puramente lineal integrado por el world
- destruir() pone velocity=0, angular=0, radius=0
- postUpdate() sincroniza center_ desde body_.position
- setVelocity(speed) mantiene la direccion, cambia solo la magnitud

Renames a camelBack (.clang-tidy del proyecto):
- get_drotacio -> getRotationDelta
- get_base_velocity -> getBaseVelocity, get_base_rotation -> getBaseRotation
- set_ship_position -> setShipPosition
- set_velocity -> setVelocity, set_rotation -> setRotation
- set_tracking_strength -> setTrackingStrength
- get_temps_invulnerabilitat -> getInvulnerabilityTime
- actualitzar_animacio -> updateAnimation
- actualitzar_palpitacio -> updatePalpitation
- actualitzar_rotacio_accelerada -> updateRotationAcceleration
- comportament_pentagon/quadrat/molinillo -> behaviorPentagon/Quadrat/Molinillo
- calcular_escala_actual -> computeCurrentScale
- intent_spawn_safe -> attemptSafeSpawn
(callsites actualizados en spawn_controller y game_scene)

Cambios en GameScene:
- En init(): physics_world_.addBody(&enemy.getBody()) por cada slot
  (los inactivos tienen radius=0, no estorban)
- En update(): postUpdate() de cada enemy tras physics_world_.update

Cambios de comportamiento visibles esperados:
- Enemigos rebotan elasticamente contra paredes (restitution=1.0)
- Enemigos se chocan entre si (impulsos elasticos con masas distintas
  por tipo: Quadrat empuja mas, Molinillo rebota mas)
- Pentagon zigzag periodico en lugar de solo al chocar pared
- Molinillo: comportamiento mas predecible (linea recta)

Aviso: Bullet sigue con su movimiento ad-hoc (Fase 6e pendiente).

Smoke test xvfb OK. Validacion gameplay del usuario pendiente.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-19 13:41:05 +02:00
parent 2fe22ff911
commit 27242f54fe
5 changed files with 325 additions and 423 deletions
+10 -4
View File
@@ -150,7 +150,7 @@ void GameScene::init() {
stage_manager_->init();
// [NEW] Set ship position reference for safe spawn (P1 for now, TODO: dual tracking)
stage_manager_->getSpawnController().set_ship_position(&ships_[0].getCenter());
stage_manager_->getSpawnController().setShipPosition(&ships_[0].getCenter());
// Inicialitzar timers de muerte per player
hit_timer_per_player_[0] = 0.0F;
@@ -195,10 +195,13 @@ void GameScene::init() {
}
}
// [MODIFIED] Initialize enemies as inactive (stage system will spawn them)
// [MODIFIED] Initialize enemies as inactive (stage system will spawn them).
// Registramos el body al world incluso inactivo: con radius=0 no colisiona
// ni se mueve, y al init() del stage system se activa sin re-registrar.
for (auto& enemy : enemies_) {
enemy = Enemy(sdl_.getRenderer());
enemy.set_ship_position(&ships_[0].getCenter()); // Set ship reference (P1 for now)
enemy.setShipPosition(&ships_[0].getCenter()); // Set ship reference (P1 for now)
physics_world_.addBody(&enemy.getBody());
// DON'T call enemy.init() here - stage system handles spawning
}
@@ -224,6 +227,9 @@ void GameScene::update(float delta_time) {
for (auto& ship : ships_) {
ship.postUpdate(delta_time);
}
for (auto& enemy : enemies_) {
enemy.postUpdate(delta_time);
}
// Processar disparos (state-based, no event-based)
if (game_over_state_ == GameOverState::NONE) {
@@ -1009,7 +1015,7 @@ void GameScene::detectar_col·lisions_bales_enemics() {
VELOCITAT_EXPLOSIO, // 50 px/s (explosión suau)
enemy.getBrightness(), // Heredar brightness
vel_enemic, // Heredar velocity
enemy.get_drotacio(), // Heredar velocity angular (trayectorias curvas)
enemy.getRotationDelta(), // Heredar velocity angular (trayectorias curvas)
0.0F // Sin herencia visual (rotación aleatoria)
);