// debris_manager.hpp - Gestor de fragments de explosions // © 2026 JailDesigner #pragma once #include #include #include #include #include #include #include "core/defaults.hpp" #include "core/graphics/shape.hpp" #include "core/rendering/render_context.hpp" #include "core/types.hpp" #include "debris.hpp" namespace Effects { // Gestor de fragments de explosions // Manté un pool de objectes Debris i gestiona el seu cicle de vida class DebrisManager { public: // Notificació opcional cada vegada que es genera una explosió. El // consumidor pot usar-la per fer reaccionar elements del fons (border // bumps, pulse del playfield, etc.). using ExplosionCallback = std::function; explicit DebrisManager(Rendering::Renderer* renderer); void setExplosionCallback(ExplosionCallback callback) { explosion_callback_ = std::move(callback); } // Crear explosión a partir de una shape // - shape: shape vectorial a explode // - centro: posición del centro de l'objecte // - angle: orientació de l'objecte (radians) // - scale: scale de l'objecte (1.0 = normal) // - velocitat_base: velocity inicial dels fragments (px/s) // - brightness: factor de brightness heretat (0.0-1.0, per defecte 1.0) // - velocitat_objecte: velocity de l'objecte que explota (px/s, per defecte 0) // - velocitat_angular: velocity angular heretada (rad/s, per defecte 0) // - factor_herencia_visual: factor de herència rotación visual (0.0-1.0, per defecte 0.0) // - lifetime: temps de vida del debris (s, per defecte TEMPS_VIDA = 2s) // - friction: desacceleració del debris (px/s², per defecte ACCELERACIO = -60) // - segment_multiplier: nombre de còpies per segment (per defecte 1 = sense duplicar) // - bullet_impulse_velocity: velocitat de la bala que ha causat l'impacte (px/s, // per defecte 0). S'aplica a cada fragment escalada per // Defaults::Physics::Debris::BULLET_IMPULSE_FACTOR, independent de // velocitat_objecte. Permet que els trossos "salten amb la força de la bala" // encara que el cos sigui pesat i amb prou feines es mogui. // - piece_scale: multiplicador de la longitud de cada fragment al spawn // (per defecte 1.0). Útil per a debris "parcial" d'impactes no letals // en enemics HP>1 (trossos petits, com d'esquerda). void explode(const std::shared_ptr& shape, const Vec2& centro, float angle, float scale, float velocitat_base, float brightness = 1.0F, const Vec2& velocitat_objecte = {.x = 0.0F, .y = 0.0F}, float velocitat_angular = 0.0F, float factor_herencia_visual = 0.0F, // sound: nom del so d'explosió. Cadena buida ("") = explosió silenciosa. const std::string& sound = Defaults::Sound::ENEMY_EXPLOSION, SDL_Color color = {0, 0, 0, 0}, // alpha==0 → fragmentos usan oscilador global float lifetime = Defaults::Physics::Debris::TEMPS_VIDA, float friction = Defaults::Physics::Debris::ACCELERACIO, int segment_multiplier = 1, const Vec2& bullet_impulse_velocity = {.x = 0.0F, .y = 0.0F}, float piece_scale = 1.0F); // Actualitzar todos los fragments active void update(float delta_time); // Dibuixar todos los fragments active void draw() const; // Reiniciar todos los fragments (clear) void reset(); // Obtenir número de fragments active [[nodiscard]] auto getActiveCount() const -> int; private: Rendering::Renderer* renderer_; ExplosionCallback explosion_callback_; // Pool de fragments (màxim concurrent) // Pentàgon 5 línies × 15 enemics × multiplier 3 = 225 trossos només d'enemics. // + ship (3 línies) + balas (5 línies × 3) = ~243. Arrodonit a 300. static constexpr int MAX_DEBRIS = 300; std::array debris_pool_; // Trobar primer slot inactiu auto findFreeSlot() -> Debris*; // Calcular direcció de explosión (radial, des del centro hacia el segment). // Estático: solo opera sobre los puntos pasados, sin estado del manager. [[nodiscard]] static auto computeExplosionDirection(const Vec2& p1, const Vec2& p2, const Vec2& centre_objecte) -> Vec2; // Sub-pasos de explode() (descomposició per reduir complexitat cognitiva). // extractSegments y los apply* son static (solo toquen el debris pasado). [[nodiscard]] static auto extractSegments(const Graphics::ShapePrimitive& primitive) -> std::vector>; // Inicialitza un debris en un slot lliure i el deixa actiu. Retorna // false si el pool está ple (la cridadora ha d'aturar el bucle). auto spawnDebris(const Vec2& world_p1, const Vec2& world_p2, const Vec2& centro, float velocitat_base, float brightness, const Vec2& velocitat_objecte, float velocitat_angular, float factor_herencia_visual, SDL_Color color, float lifetime, float friction, const Vec2& bullet_impulse_velocity, float piece_scale) -> bool; static void applyAngularVelocity(Debris& debris, const Vec2& direccio, float velocitat_angular); static void applyVisualRotation(Debris& debris, float velocitat_angular, float factor_herencia_visual); }; } // namespace Effects