From 87b96b8226c08e32db58ab9016613534bee17b51 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 21 May 2026 14:05:10 +0200 Subject: [PATCH] fix(debris): bugs rotacion cuadratica y shrink exponencial (geometria autoritativa) --- source/game/effects/debris.hpp | 21 +++++++--- source/game/effects/debris_manager.cpp | 58 +++++++++++++------------- 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/source/game/effects/debris.hpp b/source/game/effects/debris.hpp index bc8f365..53eeb80 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 per a la geometria): + // centro + original_angle (orientació spawn) + angle_rotacio (acumulat) + // + original_half_length × shrink_factor (mida actual) + // p1/p2 es reconstrueixen cada frame en update() des d'aquestes dades, mai + // de forma iterativa — 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 9d6bdfc..9b8cc3f 100644 --- a/source/game/effects/debris_manager.cpp +++ b/source/game/effects/debris_manager.cpp @@ -112,7 +112,14 @@ namespace Effects { 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; @@ -319,40 +326,33 @@ namespace Effects { } } - // 3. Calcular centro del segment - Vec2 centro = {.x = (debris.p1.x + debris.p2.x) / 2.0F, - .y = (debris.p1.y + debris.p2.y) / 2.0F}; + // 3. Actualitzar posició del centre (integra velocity). + debris.centro.x += debris.velocity.x * delta_time; + debris.centro.y += debris.velocity.y * delta_time; - // 4. Actualitzar posición del centro - centro.x += debris.velocity.x * delta_time; - centro.y += debris.velocity.y * delta_time; + // 4. Rebot contra els límits del PLAYAREA. + bounceOffPlayArea(debris.centro, debris.velocity); - // 4b. Rebot contra els límits del PLAYAREA. - bounceOffPlayArea(centro, debris.velocity); - - // 5. Actualitzar rotación VISUAL + // 5. Actualitzar rotació visual acumulada. debris.angle_rotacio += debris.velocitat_rot_visual * delta_time; - // 6. Aplicar shrinking (reducció de distancia entre points). - // El shrink es normalitza al min_lifetime (capat a 1.0) perquè els - // fragments que viuen més no es continuïn fent més petits per sempre. + // 6. Shrink lineal sobre la longitud ORIGINAL (no iteratiu). + // SHRINK_T va de 0 a 1 al llarg de min_lifetime; després queda + // a 1 i el shrink_factor manté el valor mínim (1 - factor_shrink). const float SHRINK_T = std::min(debris.temps_vida / debris.min_lifetime, 1.0F); - float shrink_factor = 1.0F - (debris.factor_shrink * SHRINK_T); - shrink_factor = std::max(0.0F, shrink_factor); // No negatiu + const float SHRINK_FACTOR = std::max(0.0F, 1.0F - (debris.factor_shrink * SHRINK_T)); - // Calcular distancia original entre points - 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)); + // 7. Reconstruir p1/p2 des de la geometria autoritaritzada: + // centro + (cos/sin(original_angle + angle_rotacio)) × original_half_length × shrink_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 * SHRINK_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); } }