fix(debris): bugs rotacion cuadratica y shrink exponencial (geometria autoritativa)

This commit is contained in:
2026-05-21 14:05:10 +02:00
parent 7505de074c
commit 87b96b8226
2 changed files with 45 additions and 34 deletions
+16 -5
View File
@@ -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)
+29 -29
View File
@@ -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);
}
}