fix(debris): bug rotacion cuadratica + shrink exponencial; geometria autoritativa

This commit is contained in:
2026-05-21 13:37:12 +02:00
parent e84f555a66
commit 9b25e875f3
5 changed files with 55 additions and 38 deletions
+30 -28
View File
@@ -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);
}
}