112 lines
5.2 KiB
C++
112 lines
5.2 KiB
C++
// debris_manager.hpp - Gestor de fragments de explosions
|
||
// © 2026 JailDesigner
|
||
|
||
#pragma once
|
||
|
||
#include <SDL3/SDL.h>
|
||
|
||
#include <array>
|
||
#include <functional>
|
||
#include <memory>
|
||
#include <utility>
|
||
#include <vector>
|
||
|
||
#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<void(Vec2 center)>;
|
||
|
||
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.
|
||
void explode(const std::shared_ptr<Graphics::Shape>& 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,
|
||
const std::string& sound = Defaults::Sound::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});
|
||
|
||
// 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, MAX_DEBRIS> 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<std::pair<Vec2, Vec2>>;
|
||
// 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) -> 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
|