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:
@@ -1,39 +1,37 @@
|
||||
// enemy.hpp - Clase para enemigos (ORNIs pentágonos)
|
||||
// enemy.hpp - Clase para enemigos (ORNIs)
|
||||
// © 1999 Visente i Sergi (versión Pascal)
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
|
||||
#include "core/defaults.hpp"
|
||||
#include "core/entities/entity.hpp"
|
||||
#include "core/types.hpp"
|
||||
#include "game/constants.hpp"
|
||||
|
||||
// Tipo de enemy
|
||||
enum class EnemyType : uint8_t {
|
||||
PENTAGON = 0, // Pentágono esquivador (zigzag)
|
||||
QUADRAT = 1, // Cuadrado perseguidor (tracks ship)
|
||||
MOLINILLO = 2 // Molinillo agressiu (fast, spinning)
|
||||
MOLINILLO = 2 // Molinillo agresivo (rápido, girando)
|
||||
};
|
||||
|
||||
// Estat de animación (palpitació i rotación accelerada)
|
||||
// Estado de animación (palpitación + rotación acelerada)
|
||||
struct EnemyAnimation {
|
||||
// Palpitation (breathing effect)
|
||||
// Palpitación (efecto respiración)
|
||||
bool palpitacio_activa = false;
|
||||
float palpitacio_fase = 0.0F; // Phase in cycle (0.0-2π)
|
||||
float palpitacio_frequencia = 2.0F; // Hz (cycles per second)
|
||||
float palpitacio_amplitud = 0.15F; // Scale variation (±15%)
|
||||
float palpitacio_temps_restant = 0.0F; // Time remaining (seconds)
|
||||
float palpitacio_fase = 0.0F;
|
||||
float palpitacio_frequencia = 2.0F;
|
||||
float palpitacio_amplitud = 0.15F;
|
||||
float palpitacio_temps_restant = 0.0F;
|
||||
|
||||
// Rotation acceleration (long-term spin modulation)
|
||||
float drotacio_base = 0.0F; // Base rotation speed (rad/s)
|
||||
float drotacio_objetivo = 0.0F; // Target rotation speed (rad/s)
|
||||
float drotacio_t = 0.0F; // Interpolation progress (0.0-1.0)
|
||||
float drotacio_duracio = 0.0F; // Duration of transition (seconds)
|
||||
// Aceleración de rotación visual (modulación a largo plazo)
|
||||
float drotacio_base = 0.0F;
|
||||
float drotacio_objetivo = 0.0F;
|
||||
float drotacio_t = 0.0F;
|
||||
float drotacio_duracio = 0.0F;
|
||||
};
|
||||
|
||||
class Enemy : public Entities::Entity {
|
||||
@@ -45,79 +43,78 @@ class Enemy : public Entities::Entity {
|
||||
void init() override { init(EnemyType::PENTAGON, nullptr); }
|
||||
void init(EnemyType type, const Vec2* ship_pos = nullptr);
|
||||
void update(float delta_time) override;
|
||||
void postUpdate(float delta_time) override;
|
||||
void draw() const override;
|
||||
|
||||
// Override: Interfície d'Entity
|
||||
[[nodiscard]] bool isActive() const override { return esta_; }
|
||||
// Override: Interfaz de Entity
|
||||
[[nodiscard]] auto isActive() const -> bool override { return esta_; }
|
||||
|
||||
// Override: Interfície de colisión
|
||||
[[nodiscard]] float getCollisionRadius() const override {
|
||||
// Override: Interfaz de colisión
|
||||
[[nodiscard]] auto getCollisionRadius() const -> float override {
|
||||
return Defaults::Entities::ENEMY_RADIUS;
|
||||
}
|
||||
[[nodiscard]] bool isCollidable() const override {
|
||||
[[nodiscard]] auto isCollidable() const -> bool override {
|
||||
return esta_ && timer_invulnerabilitat_ <= 0.0F;
|
||||
}
|
||||
|
||||
// Getters (API pública sin canvis)
|
||||
void destruir() { esta_ = false; }
|
||||
[[nodiscard]] float get_drotacio() const { return drotacio_; }
|
||||
[[nodiscard]] Vec2 getVelocityVector() const {
|
||||
return {
|
||||
.x = velocity_ * std::cos(angle_ - (Constants::PI / 2.0F)),
|
||||
.y = velocity_ * std::sin(angle_ - (Constants::PI / 2.0F))};
|
||||
}
|
||||
// Marcar destruido (desactiva el cuerpo físicamente: radius=0)
|
||||
void destruir();
|
||||
|
||||
// Getters
|
||||
[[nodiscard]] auto getRotationDelta() const -> float { return drotacio_; }
|
||||
[[nodiscard]] auto getVelocityVector() const -> Vec2 { return body_.velocity; }
|
||||
|
||||
// Set ship position reference for tracking behavior
|
||||
void set_ship_position(const Vec2* ship_pos) { ship_position_ = ship_pos; }
|
||||
void setShipPosition(const Vec2* ship_pos) { ship_position_ = ship_pos; }
|
||||
|
||||
// [NEW] Getters for stage system (base stats)
|
||||
[[nodiscard]] float get_base_velocity() const;
|
||||
[[nodiscard]] float get_base_rotation() const;
|
||||
[[nodiscard]] EnemyType getType() const { return type_; }
|
||||
// Stage system API (base stats)
|
||||
[[nodiscard]] auto getBaseVelocity() const -> float;
|
||||
[[nodiscard]] auto getBaseRotation() const -> float;
|
||||
[[nodiscard]] auto getType() const -> EnemyType { return type_; }
|
||||
|
||||
// [NEW] Setters for difficulty multipliers (stage system)
|
||||
void set_velocity(float vel) { velocity_ = vel; }
|
||||
void set_rotation(float rot) {
|
||||
// Setters para multiplicadores de dificultad (stage system).
|
||||
// Establecen la velocidad escalar deseada manteniendo la dirección
|
||||
// actual del body_.velocity.
|
||||
void setVelocity(float speed);
|
||||
void setRotation(float rot) {
|
||||
drotacio_ = rot;
|
||||
animacio_.drotacio_base = rot;
|
||||
}
|
||||
void set_tracking_strength(float strength);
|
||||
void setTrackingStrength(float strength);
|
||||
|
||||
// [NEW] Invulnerability queries
|
||||
[[nodiscard]] bool isInvulnerable() const { return timer_invulnerabilitat_ > 0.0F; }
|
||||
[[nodiscard]] float get_temps_invulnerabilitat() const { return timer_invulnerabilitat_; }
|
||||
// Invulnerabilidad
|
||||
[[nodiscard]] auto isInvulnerable() const -> bool { return timer_invulnerabilitat_ > 0.0F; }
|
||||
[[nodiscard]] auto getInvulnerabilityTime() const -> float { return timer_invulnerabilitat_; }
|
||||
|
||||
private:
|
||||
// Membres específics d'Enemy (heretats: renderer_, shape_, center_, angle_, brightness_)
|
||||
float velocity_;
|
||||
float drotacio_; // Delta rotación visual (rad/s)
|
||||
float rotacio_; // Rotación visual acumulada
|
||||
// Miembros específicos (heredados: renderer_, shape_, center_, angle_, brightness_, body_)
|
||||
float drotacio_; // Velocidad angular visual (rad/s) — solo decoración, separada de body_.angular_velocity
|
||||
float rotacio_; // Rotación visual acumulada (no afecta movimiento)
|
||||
bool esta_;
|
||||
|
||||
// [NEW] Enemy type and configuration
|
||||
EnemyType type_;
|
||||
|
||||
// [NEW] Animation state
|
||||
EnemyAnimation animacio_;
|
||||
|
||||
// [NEW] Behavior state (type-specific)
|
||||
float tracking_timer_; // For Cuadrado: time since last angle update
|
||||
const Vec2* ship_position_; // Pointer to ship position (for tracking)
|
||||
float tracking_strength_; // For Cuadrado: tracking intensity (0.0-1.5), default 0.5
|
||||
// Comportamiento type-specific
|
||||
float tracking_timer_; // Quadrat: tiempo desde último update de dirección
|
||||
const Vec2* ship_position_; // Puntero a posición de la nave (para tracking)
|
||||
float tracking_strength_; // Quadrat: intensidad de tracking (0.0-1.5), default 0.5
|
||||
float direction_change_timer_; // Pentagon: tiempo para próximo cambio de dirección
|
||||
|
||||
// [NEW] Invulnerability state
|
||||
float timer_invulnerabilitat_; // Countdown timer (seconds), 0.0f = vulnerable
|
||||
// Invulnerabilidad post-spawn
|
||||
float timer_invulnerabilitat_;
|
||||
|
||||
// [EXISTING] Private methods
|
||||
void mou(float delta_time);
|
||||
// Métodos privados
|
||||
void updateAnimation(float delta_time);
|
||||
void updatePalpitation(float delta_time);
|
||||
void updateRotationAcceleration(float delta_time);
|
||||
void behaviorPentagon(float delta_time);
|
||||
void behaviorQuadrat(float delta_time);
|
||||
void behaviorMolinillo(float delta_time);
|
||||
[[nodiscard]] auto computeCurrentScale() const -> float;
|
||||
auto attemptSafeSpawn(const Vec2& ship_pos, float& out_x, float& out_y) -> bool;
|
||||
|
||||
// [NEW] Private methods
|
||||
void actualitzar_animacio(float delta_time);
|
||||
void actualitzar_palpitacio(float delta_time);
|
||||
void actualitzar_rotacio_accelerada(float delta_time);
|
||||
void comportament_pentagon(float delta_time);
|
||||
void comportament_quadrat(float delta_time);
|
||||
void comportament_molinillo(float delta_time);
|
||||
[[nodiscard]] float calcular_escala_actual() const; // Returns scale with palpitation applied
|
||||
bool intent_spawn_safe(const Vec2& ship_pos, float& out_x, float& out_y);
|
||||
// Helper: setear body_.velocity desde un ángulo y magnitud.
|
||||
// angle_movement=0 apunta hacia arriba (eje Y negativo SDL).
|
||||
void setVelocityFromAngle(float angle_movement, float speed);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user