refactor(debris): la bala impacta al cos O als trossos, mai a tots dos

This commit is contained in:
2026-05-25 21:26:32 +02:00
parent b511740d93
commit 610eaf257e
8 changed files with 87 additions and 32 deletions
+20 -14
View File
@@ -150,7 +150,9 @@ namespace Systems::Collision {
const float DEATH_FACTOR = ctx.ships[i].getConfig().physics.death_impact_factor;
const Vec2 IMPULSE = SHIP_VEL * (ctx.ships[i].getBody().mass * DEATH_FACTOR);
touched_enemy->applyImpulse(IMPULSE);
ctx.on_player_hit(i);
// Sense bala: cap impuls de bala per als debris (mort per
// col·lisió cos-cos). Els debris hereten la inèrcia del ship.
ctx.on_player_hit(i, Vec2{});
} else {
// Primer impacte → estat HURT (rebot físic ja resolt per PhysicsWorld;
// l'enemic no rep dany per decisió de disseny).
@@ -197,13 +199,12 @@ namespace Systems::Collision {
}
// *** TEAMMATE HIT (friendly fire) ***
// Víctima perd 1 vida, atacant en guanya 1. Apliquem l'impuls
// de la bala a la nau ABANS de on_player_hit perquè tocado()
// captura la velocitat per als debris (si no, queden quiets).
const Vec2 BULLET_IMPULSE = bullet.getBody().velocity *
(bullet.getBody().mass * bullet.getConfig().physics.impact_momentum_factor);
ctx.ships[player_id].getBody().applyImpulse(BULLET_IMPULSE);
ctx.on_player_hit(player_id);
// Víctima perd 1 vida, atacant en guanya 1. Friendly fire sempre
// mata: el bullet va als debris (via tocado) i NO al cos del ship
// — el cos està a punt de desactivar-se, qualsevol impuls seria
// double-count amb la velocitat que ja reben els trossos.
const Vec2 BULLET_VEL = bullet.getBody().velocity;
ctx.on_player_hit(player_id, BULLET_VEL);
ctx.lives_per_player[BULLET_OWNER]++;
Audio::get()->playSound(Defaults::Sound::FRIENDLY_FIRE_HIT, Audio::Group::GAME);
breakBullet(ctx.debris_manager, bullet);
@@ -237,15 +238,20 @@ namespace Systems::Collision {
}
// *** BALA D'ENEMIC → SHIP ***
// Apliquem l'impuls de la bala abans del hurt/death perquè la
// velocitat de la nau quedi capturada per als debris.
const Vec2 IMPULSE = bullet.getBody().velocity *
(bullet.getBody().mass * bullet.getConfig().physics.impact_momentum_factor);
ctx.ships[player_id].getBody().applyImpulse(IMPULSE);
// Regla "cos XOR trossos": l'impuls de la bala s'aplica al cos
// només si el ship sobreviu (fereix). Si el ship mor, el bullet
// va directament als trossos (via tocado) i el cos no rep impuls
// — els trossos ja porten la força de la bala, qualsevol impuls
// afegit al cos seria double-count.
const Vec2 BULLET_VEL = bullet.getBody().velocity;
if (ctx.ships[player_id].isHurt()) {
// Segon impacte durant HURT → mort.
ctx.on_player_hit(player_id);
ctx.on_player_hit(player_id, BULLET_VEL);
} else {
// Fereix: el cos sobreviu, rep l'impuls. No hi ha debris encara.
const Vec2 IMPULSE = BULLET_VEL *
(bullet.getBody().mass * bullet.getConfig().physics.impact_momentum_factor);
ctx.ships[player_id].getBody().applyImpulse(IMPULSE);
ctx.ships[player_id].hurt();
}
breakBullet(ctx.debris_manager, bullet);
+5 -2
View File
@@ -40,8 +40,11 @@ namespace Systems::Collision {
Effects::FireworkManager& firework_manager;
Effects::FloatingScoreManager& floating_score_manager;
const GameConfig::MatchConfig& match_config;
// Trigger de muerte del jugador (GameScene::tocado).
std::function<void(uint8_t /*player_id*/)> on_player_hit;
// Trigger de muerte del jugador (GameScene::tocado). bullet_velocity es
// la velocitat de la bala que ha causat la mort (Vec2{} si la mort no
// ve d'una bala — col·lisió ship-enemy, etc.). Es passa al debris perquè
// els trossos volin en direcció de la bala.
std::function<void(uint8_t /*player_id*/, const Vec2& /*bullet_velocity*/)> on_player_hit;
};
// Detecta colisiones bullet → enemy. Si hit:
+26 -4
View File
@@ -24,10 +24,11 @@ namespace Systems::EnemyEvents {
ctx.floating_score_manager.crear(POINTS, enemy.getCenter());
}
void doCreateDebris(Systems::Collision::Context& ctx, const Enemy& enemy) {
void doCreateDebris(Systems::Collision::Context& ctx, const Enemy& enemy, const Bullet* bullet) {
constexpr float SPEED_EXPLOSIO = 80.0F;
const Vec2 INHERITED_VEL = enemy.getVelocityVector() *
Defaults::Physics::Debris::ENEMY_VELOCITY_INHERITANCE;
const Vec2 BULLET_VEL = (bullet != nullptr) ? bullet->getBody().velocity : Vec2{};
ctx.debris_manager.explode(
enemy.getShape(),
enemy.getCenter(),
@@ -42,7 +43,8 @@ namespace Systems::EnemyEvents {
enemy.getConfig().colors.normal,
Defaults::Physics::Debris::ENEMY_LIFETIME,
Defaults::Physics::Debris::ENEMY_FRICTION,
Defaults::Physics::Debris::ENEMY_SEGMENT_MULTIPLIER);
Defaults::Physics::Debris::ENEMY_SEGMENT_MULTIPLIER,
BULLET_VEL);
}
void doCreateFireworks(Systems::Collision::Context& ctx, const Enemy& enemy) {
@@ -67,6 +69,24 @@ namespace Systems::EnemyEvents {
void dispatchEvent(Systems::Collision::Context& ctx, Enemy& enemy, EnemyEventType event, uint8_t shooter_id, const Bullet* bullet) {
const auto& actions = enemy.getConfig().events.getActions(event);
// Pre-scan: aquest event matarà l'enemic? Si sí, l'impuls de la bala
// va directament als debris (via doCreateDebris) i NO s'aplica al cos
// — així evitem el "double-count" on els trossos hereten la velocitat
// del cos (boostat per la bala) I a més el seu propi impuls de bala.
// Regla: el bullet impacta al cos O als trossos, mai a tots dos.
bool will_die = false;
for (const auto& action : actions) {
if (action.type == EnemyActionType::DESTROY) {
will_die = true;
break;
}
if (action.type == EnemyActionType::SET_HURT && enemy.isWounded()) {
will_die = true;
break;
}
}
for (const auto& action : actions) {
switch (action.type) {
case EnemyActionType::SET_HURT:
@@ -86,13 +106,15 @@ namespace Systems::EnemyEvents {
doAddScore(ctx, enemy, shooter_id);
break;
case EnemyActionType::CREATE_DEBRIS:
doCreateDebris(ctx, enemy);
doCreateDebris(ctx, enemy, bullet);
break;
case EnemyActionType::CREATE_FIREWORKS:
doCreateFireworks(ctx, enemy);
break;
case EnemyActionType::APPLY_IMPULSE:
doApplyImpulse(enemy, bullet);
if (!will_die) {
doApplyImpulse(enemy, bullet);
}
break;
}
}