// enemy.hpp - Clase para enemigos (ORNIs) // © 2026 JailDesigner #pragma once #include #include #include "core/defaults.hpp" #include "core/entities/entity.hpp" #include "core/types.hpp" // Tipo de enemy enum class EnemyType : uint8_t { PENTAGON = 0, // Pentágono esquivador (zigzag) QUADRAT = 1, // Cuadrado perseguidor (tracks ship) MOLINILLO = 2 // Molinillo agresivo (rápido, girando) }; // Estado de animación (palpitación + rotación acelerada) struct EnemyAnimation { // Palpitación (efecto respiración) bool palpitacio_activa = false; float palpitacio_fase = 0.0F; float palpitacio_frequencia = 2.0F; float palpitacio_amplitud = 0.15F; float palpitacio_temps_restant = 0.0F; // 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 { public: Enemy() : Entity(nullptr) {} explicit Enemy(Rendering::Renderer* renderer); 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: Interfaz de Entity [[nodiscard]] auto isActive() const -> bool override { return esta_; } // Override: Interfaz de colisión [[nodiscard]] auto getCollisionRadius() const -> float override { return Defaults::Entities::ENEMY_RADIUS; } [[nodiscard]] auto isCollidable() const -> bool override { return esta_ && timer_invulnerabilitat_ <= 0.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 setShipPosition(const Vec2* ship_pos) { ship_position_ = ship_pos; } // Stage system API (base stats) [[nodiscard]] auto getBaseVelocity() const -> float; [[nodiscard]] auto getBaseRotation() const -> float; [[nodiscard]] auto getType() const -> EnemyType { return type_; } // 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 setTrackingStrength(float strength); // Invulnerabilidad [[nodiscard]] auto isInvulnerable() const -> bool { return timer_invulnerabilitat_ > 0.0F; } [[nodiscard]] auto getInvulnerabilityTime() const -> float { return timer_invulnerabilitat_; } private: // Miembros específicos (heredados: renderer_, shape_, center_, angle_, brightness_, body_). // Inicializados en la declaración: el ctor por defecto deja al enemy en estado "inactivo // como pentágono", coherente con lo que harán init() o el ctor con renderer al activarlo. float drotacio_{0.0F}; // Velocidad angular visual (rad/s) — solo decoración, separada de body_.angular_velocity float rotacio_{0.0F}; // Rotación visual acumulada (no afecta movimiento) bool esta_{false}; EnemyType type_{EnemyType::PENTAGON}; EnemyAnimation animacio_; // Comportamiento type-specific float tracking_timer_{0.0F}; // Quadrat: tiempo desde último update de dirección const Vec2* ship_position_{nullptr}; // Puntero a posición de la nave (para tracking) float tracking_strength_{0.0F}; // Quadrat: intensidad de tracking (0.0-1.5), default 0.5 float direction_change_timer_{0.0F}; // Pentagon: tiempo para próximo cambio de dirección // Invulnerabilidad post-spawn float timer_invulnerabilitat_{0.0F}; // 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; // Estático: solo opera sobre ship_pos pasado; no consulta estado del enemy. static auto attemptSafeSpawn(const Vec2& ship_pos, float& out_x, float& out_y) -> bool; // 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); };