feat(debris): modelo INTACTO→MENGUANDO→0 (sin pop, fade-out por tamaño)

This commit is contained in:
2026-05-21 12:53:01 +02:00
parent efd18ff852
commit 048263a1d0
5 changed files with 105 additions and 101 deletions
+81 -80
View File
@@ -136,11 +136,14 @@ namespace Effects {
debris->angle_rotacio = 0.0F;
// Vida i shrinking — min_lifetime és el temps mínim garantit; després
// el fragment mor quan |velocity| < MIN_SPEED_TO_DIE.
// 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.
debris->temps_vida = 0.0F;
debris->min_lifetime = lifetime;
debris->factor_shrink = Defaults::Physics::Debris::SHRINK_RATE;
debris->intact_time = lifetime;
debris->shrinking = false;
debris->size_factor = 1.0F;
debris->shrink_rate = Defaults::Physics::Debris::SHRINK_RATE;
// Visuals heretades
debris->brightness = brightness;
@@ -212,102 +215,100 @@ namespace Effects {
}
}
// INTACTE → MENGUANT → mort. Retorna true si el debris segueix viu.
static auto updateLifecycle(Debris& debris, float delta_time) -> bool {
debris.temps_vida += delta_time;
const float SPEED_SQ = (debris.velocity.x * debris.velocity.x) +
(debris.velocity.y * debris.velocity.y);
if (!debris.shrinking) {
const bool TIME_TRIGGER = debris.temps_vida >= debris.intact_time;
const bool SPEED_TRIGGER = SPEED_SQ < Defaults::Physics::Debris::SHRINK_SPEED_THRESHOLD_SQ;
if (TIME_TRIGGER || SPEED_TRIGGER) {
debris.shrinking = true;
}
}
if (debris.shrinking) {
debris.size_factor -= debris.shrink_rate * delta_time;
if (debris.size_factor <= 0.0F) {
debris.active = false;
return false;
}
}
return true;
}
// Fricció lineal: redueix |velocity| en acceleration per segon.
static void applyLinearFriction(Debris& debris, float delta_time) {
const float SPEED = std::sqrt((debris.velocity.x * debris.velocity.x) +
(debris.velocity.y * debris.velocity.y));
if (SPEED > 1.0F) {
const float DIR_X = debris.velocity.x / SPEED;
const float DIR_Y = debris.velocity.y / SPEED;
const float NEW_SPEED = std::max(SPEED + (debris.acceleration * delta_time), 0.0F);
debris.velocity.x = DIR_X * NEW_SPEED;
debris.velocity.y = DIR_Y * NEW_SPEED;
} else {
debris.velocity.x = 0.0F;
debris.velocity.y = 0.0F;
}
}
// Rota el vector velocity (trajectòria corba) i aplica fricció angular.
static void applyAngularDynamics(Debris& debris, float delta_time) {
if (std::abs(debris.velocitat_rot) <= 0.01F) {
return;
}
// Rotar vector de velocity amb matriu 2D
const float DANGLE = debris.velocitat_rot * delta_time;
const float VX = debris.velocity.x;
const float VY = debris.velocity.y;
const float COS_A = std::cos(DANGLE);
const float SIN_A = std::sin(DANGLE);
debris.velocity.x = (VX * COS_A) - (VY * SIN_A);
debris.velocity.y = (VX * SIN_A) + (VY * COS_A);
// Fricció angular (desacceleració gradual)
const float SIGN = (debris.velocitat_rot > 0) ? 1.0F : -1.0F;
const float REDUCCION = Defaults::Physics::Debris::FRICCIO_ANGULAR * delta_time;
debris.velocitat_rot -= SIGN * REDUCCION;
if ((debris.velocitat_rot > 0) != (SIGN > 0)) {
debris.velocitat_rot = 0.0F;
}
}
void DebrisManager::update(float delta_time) {
for (auto& debris : debris_pool_) {
if (!debris.active) {
continue;
}
// 1. Actualitzar time de vida
debris.temps_vida += delta_time;
// Política de mort: viu sí o sí durant min_lifetime; després mor
// quan la velocity cau per sota d'un llindar. Així els fragments
// ràpids no desapareixen en moviment.
if (debris.temps_vida >= debris.min_lifetime) {
const float SPEED_SQ = (debris.velocity.x * debris.velocity.x) +
(debris.velocity.y * debris.velocity.y);
if (SPEED_SQ < Defaults::Physics::Debris::MIN_SPEED_TO_DIE_SQ) {
debris.active = false;
continue;
}
if (!updateLifecycle(debris, delta_time)) {
continue;
}
// 2. Actualitzar velocity (desacceleració)
// Aplicar fricció en la direcció del movement
float speed = std::sqrt((debris.velocity.x * debris.velocity.x) +
(debris.velocity.y * debris.velocity.y));
applyLinearFriction(debris, delta_time);
applyAngularDynamics(debris, delta_time);
if (speed > 1.0F) {
// Calcular direcció normalitzada
float dir_x = debris.velocity.x / speed;
float dir_y = debris.velocity.y / speed;
// Aplicar aceleración negativa (fricció)
float nova_speed = speed + (debris.acceleration * delta_time);
nova_speed = std::max(nova_speed, 0.0F);
debris.velocity.x = dir_x * nova_speed;
debris.velocity.y = dir_y * nova_speed;
} else {
// Velocidad mucho baixa, aturar
debris.velocity.x = 0.0F;
debris.velocity.y = 0.0F;
}
// 2b. Rotar vector de velocity (trayectoria curva)
if (std::abs(debris.velocitat_rot) > 0.01F) {
// Calcular angle de rotación este frame
float dangle = debris.velocitat_rot * delta_time;
// Rotar vector de velocity usant matriu de rotación 2D
float vel_x_old = debris.velocity.x;
float vel_y_old = debris.velocity.y;
float cos_a = std::cos(dangle);
float sin_a = std::sin(dangle);
debris.velocity.x = (vel_x_old * cos_a) - (vel_y_old * sin_a);
debris.velocity.y = (vel_x_old * sin_a) + (vel_y_old * cos_a);
}
// 2c. Aplicar fricció angular (desacceleració gradual)
if (std::abs(debris.velocitat_rot) > 0.01F) {
float sign = (debris.velocitat_rot > 0) ? 1.0F : -1.0F;
float reduccion =
Defaults::Physics::Debris::FRICCIO_ANGULAR * delta_time;
debris.velocitat_rot -= sign * reduccion;
// Evitar canvi de signe (no pot passar de CW a CCW)
if ((debris.velocitat_rot > 0) != (sign > 0)) {
debris.velocitat_rot = 0.0F;
}
}
// 3. Calcular centro del segment
// 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};
// 4. Actualitzar posición del centro
centro.x += debris.velocity.x * delta_time;
centro.y += debris.velocity.y * delta_time;
// 5. Actualitzar rotación VISUAL
// Rotació visual del segment
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.
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
// Calcular distancia original entre points
// 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 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;