diff --git a/source/core/defaults/physics.hpp b/source/core/defaults/physics.hpp index 10d942a..9f4062e 100644 --- a/source/core/defaults/physics.hpp +++ b/source/core/defaults/physics.hpp @@ -52,7 +52,8 @@ namespace Defaults::Physics { // Tuneig específic de l'explosió d'enemic (overrides als defaults // que es passen com a paràmetres opcionals a explode()). - constexpr float ENEMY_INTACT_TIME = 1.5F; // Temps intacte abans de menguar (s) + constexpr float ENEMY_INTACT_TIME = 0.5F; // Temps intacte abans de menguar (s) — comencen aviat + constexpr float ENEMY_SHRINK_RATE = 0.33F; // 1/3 per segon → 3s de fade-out lent constexpr float ENEMY_FRICTION = -30.0F; // Fricció més suau perquè s'estenguin més constexpr int ENEMY_SEGMENT_MULTIPLIER = 3; // Còpies de cada segment (5 cares × 3 = 15 trossos) diff --git a/source/game/effects/debris.hpp b/source/game/effects/debris.hpp index 62f3ce3..1211be2 100644 --- a/source/game/effects/debris.hpp +++ b/source/game/effects/debris.hpp @@ -9,18 +9,29 @@ namespace Effects { // Debris: un segment de línia que vola perpendicular a sí mismo - // Representa un fragment de una shape destruïda (ship, enemy, bullet) + // Representa un fragment de una shape destruïda (ship, enemy, bullet). + // + // Representació autoritaritzada (font de veritat): + // centro + original_angle (orientació spawn) + angle_rotacio (acumulat) + // + original_half_length × size_factor (mida actual) + // p1/p2 es reconstrueixen cada frame des d'aquestes dades — no es modifiquen + // iterativament (evita bugs de rotació quadràtica i shrink exponencial). struct Debris { - // Geometria del segment (2 points en coordenades mundials) - Vec2 p1; // Vec2 inicial del segment - Vec2 p2; // Vec2 final del segment + // Geometria del segment (2 points en coordenades mundials, derivats) + Vec2 p1; + Vec2 p2; + + // Geometria original (font de veritat, no canvia després del spawn) + Vec2 centro; // Centre actual del segment (es mou amb velocity) + float original_angle; // Orientació del segment al spawn (rad) + float original_half_length; // Mitja-longitud al spawn (px) // Física Vec2 velocity; // Velocidad en px/s (components x, y) float acceleration; // Aceleración negativa (fricció) en px/s² // Rotación - float angle_rotacio; // Angle de rotación acumulat (radians) + float angle_rotacio; // Acumulat de rotació visual des del spawn (radians) float velocitat_rot; // Velocidad de rotación de TRAYECTORIA (rad/s) float velocitat_rot_visual; // Velocidad de rotación VISUAL del segment (rad/s) diff --git a/source/game/effects/debris_manager.cpp b/source/game/effects/debris_manager.cpp index 24a90c4..08cc966 100644 --- a/source/game/effects/debris_manager.cpp +++ b/source/game/effects/debris_manager.cpp @@ -57,7 +57,8 @@ namespace Effects { SDL_Color color, float lifetime, float friction, - int segment_multiplier) { + int segment_multiplier, + float shrink_rate) { if (!shape || !shape->isValid()) { return; } @@ -79,7 +80,7 @@ namespace Effects { Vec2 world_p2 = transformPoint(local_p2, shape_centre, centro, angle, scale); // Si el pool es ple, no té sentit continuar amb la resta de segments - if (!spawnDebris(world_p1, world_p2, centro, velocitat_base, brightness, velocitat_objecte, velocitat_angular, factor_herencia_visual, color, lifetime, friction)) { + if (!spawnDebris(world_p1, world_p2, centro, velocitat_base, brightness, velocitat_objecte, velocitat_angular, factor_herencia_visual, color, lifetime, friction, shrink_rate)) { return; } } @@ -105,14 +106,21 @@ namespace Effects { return segments; } - auto DebrisManager::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) -> bool { + auto DebrisManager::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, float shrink_rate) -> bool { Debris* debris = findFreeSlot(); if (debris == nullptr) { std::cerr << "[DebrisManager] Warning: no debris slots disponibles\n"; return false; } - // Geometria + // Geometria autoritaritzada: centro + original_angle + original_half_length. + // p1/p2 es reconstrueixen cada frame en update() des d'aquestes dades. + const float DX = world_p2.x - world_p1.x; + const float DY = world_p2.y - world_p1.y; + debris->centro = {.x = (world_p1.x + world_p2.x) / 2.0F, + .y = (world_p1.y + world_p2.y) / 2.0F}; + debris->original_angle = std::atan2(DY, DX); + debris->original_half_length = std::sqrt((DX * DX) + (DY * DY)) / 2.0F; debris->p1 = world_p1; debris->p2 = world_p2; @@ -138,12 +146,12 @@ namespace Effects { // Estat inicial: INTACTE durant `lifetime` segons (o fins que la // velocity baixi de SHRINK_SPEED_THRESHOLD). Després MENGUANT a - // SHRINK_RATE per segon fins arribar a size_factor=0 → mor. + // shrink_rate per segon fins arribar a size_factor=0 → mor. debris->temps_vida = 0.0F; debris->intact_time = lifetime; debris->shrinking = false; debris->size_factor = 1.0F; - debris->shrink_rate = Defaults::Physics::Debris::SHRINK_RATE; + debris->shrink_rate = shrink_rate; // Visuals heretades debris->brightness = brightness; @@ -305,32 +313,26 @@ namespace Effects { applyLinearFriction(debris, delta_time); applyAngularDynamics(debris, delta_time); - // Posició: nou centre = centre antic + velocity · dt - Vec2 centro = {.x = (debris.p1.x + debris.p2.x) / 2.0F, - .y = (debris.p1.y + debris.p2.y) / 2.0F}; - centro.x += debris.velocity.x * delta_time; - centro.y += debris.velocity.y * delta_time; + // Posició del centre: integra velocity (separat de p1/p2). + debris.centro.x += debris.velocity.x * delta_time; + debris.centro.y += debris.velocity.y * delta_time; - // Rotació visual del segment. Modulada per size_factor: durant + // Acumular rotació visual. Modulada per size_factor: durant // INTACTE (size=1) no afecta, però quan el segment mengua la - // rotació també s'apaga, evitant l'efecte "hèlix d'avió" quan - // el segment es fa molt petit. + // rotació també s'apaga. debris.angle_rotacio += debris.velocitat_rot_visual * debris.size_factor * delta_time; - // Mida actual = size_factor (1.0 intacte, decreix durant MENGUANT) - const float SHRINK_FACTOR = std::max(0.0F, debris.size_factor); - float dx = debris.p2.x - debris.p1.x; - float dy = debris.p2.y - debris.p1.y; - - // 7. Reconstruir segment con nueva mida i rotación - float half_length = std::sqrt((dx * dx) + (dy * dy)) * SHRINK_FACTOR / 2.0F; - float original_angle = std::atan2(dy, dx); - float new_angle = original_angle + debris.angle_rotacio; - - debris.p1.x = centro.x - (half_length * std::cos(new_angle)); - debris.p1.y = centro.y - (half_length * std::sin(new_angle)); - debris.p2.x = centro.x + (half_length * std::cos(new_angle)); - debris.p2.y = centro.y + (half_length * std::sin(new_angle)); + // Reconstruir p1/p2 des de la geometria autoritaritzada: + // centro + (cos/sin(original_angle + angle_rotacio)) × original_half_length × size_factor + // No iteratiu — evita la rotació quadràtica i el shrink exponencial. + const float CURRENT_ANGLE = debris.original_angle + debris.angle_rotacio; + const float HALF_LEN = debris.original_half_length * std::max(0.0F, debris.size_factor); + const float COS_A = std::cos(CURRENT_ANGLE); + const float SIN_A = std::sin(CURRENT_ANGLE); + debris.p1.x = debris.centro.x - (HALF_LEN * COS_A); + debris.p1.y = debris.centro.y - (HALF_LEN * SIN_A); + debris.p2.x = debris.centro.x + (HALF_LEN * COS_A); + debris.p2.y = debris.centro.y + (HALF_LEN * SIN_A); } } diff --git a/source/game/effects/debris_manager.hpp b/source/game/effects/debris_manager.hpp index 95b45e2..8647b1a 100644 --- a/source/game/effects/debris_manager.hpp +++ b/source/game/effects/debris_manager.hpp @@ -34,9 +34,10 @@ namespace Effects { // - 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) + // - lifetime: temps INTACTE del debris (s, per defecte INTACT_TIME) // - friction: desacceleració del debris (px/s², per defecte ACCELERACIO = -60) // - segment_multiplier: nombre de còpies per segment (per defecte 1 = sense duplicar) + // - shrink_rate: velocity de mengua durant MENGUANT (1/s, per defecte SHRINK_RATE) void explode(const std::shared_ptr& shape, const Vec2& centro, float angle, @@ -50,7 +51,8 @@ namespace Effects { SDL_Color color = {0, 0, 0, 0}, // alpha==0 → fragmentos usan oscilador global float lifetime = Defaults::Physics::Debris::INTACT_TIME, float friction = Defaults::Physics::Debris::ACCELERACIO, - int segment_multiplier = 1); + int segment_multiplier = 1, + float shrink_rate = Defaults::Physics::Debris::SHRINK_RATE); // Actualitzar todos los fragments active void update(float delta_time); @@ -86,7 +88,7 @@ namespace Effects { -> 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) -> bool; + 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, float shrink_rate) -> bool; static void applyAngularVelocity(Debris& debris, const Vec2& direccio, float velocitat_angular); static void applyVisualRotation(Debris& debris, float velocitat_angular, float factor_herencia_visual); }; diff --git a/source/game/systems/collision_system.cpp b/source/game/systems/collision_system.cpp index f000d1e..8a63fc5 100644 --- a/source/game/systems/collision_system.cpp +++ b/source/game/systems/collision_system.cpp @@ -76,7 +76,8 @@ namespace Systems::Collision { COLOR, Defaults::Physics::Debris::ENEMY_INTACT_TIME, Defaults::Physics::Debris::ENEMY_FRICTION, - Defaults::Physics::Debris::ENEMY_SEGMENT_MULTIPLIER); + Defaults::Physics::Debris::ENEMY_SEGMENT_MULTIPLIER, + Defaults::Physics::Debris::ENEMY_SHRINK_RATE); } } // anonymous namespace