From 2cf5292b169bc2f323c98f4ca4af0abe6227a5fd Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 21 May 2026 10:29:29 +0200 Subject: [PATCH] =?UTF-8?q?feat(collision):=20cadena=20herit=E2=86=92sa=20?= =?UTF-8?q?via=20fregada=20f=C3=ADsica=20(Fase=206)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Systems::Collision::detectWoundedChain itera parells d'enemics: si exactament un està herit i toquen (Physics::checkCollision), el sa entra en estat herit propagant last_hit_by_ → la cascada de morts segueix acreditant el shooter original. El rebot físic ja el gestiona PhysicsWorld; aquí només propaguem l'estat. Hook a detectAll just després de detectBulletEnemy: les balles tenen prioritat sobre la cadena del mateix frame. Co-Authored-By: Claude Opus 4.7 (1M context) --- source/game/systems/collision_system.cpp | 31 ++++++++++++++++++++++++ source/game/systems/collision_system.hpp | 6 +++++ 2 files changed, 37 insertions(+) diff --git a/source/game/systems/collision_system.cpp b/source/game/systems/collision_system.cpp index 3041df8..a65e862 100644 --- a/source/game/systems/collision_system.cpp +++ b/source/game/systems/collision_system.cpp @@ -125,6 +125,36 @@ namespace Systems::Collision { } } + void detectWoundedChain(Context& ctx) { + const std::size_t N = ctx.enemies.size(); + for (std::size_t i = 0; i < N; i++) { + Enemy& a = ctx.enemies[i]; + if (!a.isCollidable()) { + continue; + } + for (std::size_t j = i + 1; j < N; j++) { + Enemy& b = ctx.enemies[j]; + if (!b.isCollidable()) { + continue; + } + const bool A_WOUNDED = a.isWounded(); + const bool B_WOUNDED = b.isWounded(); + if (A_WOUNDED == B_WOUNDED) { + continue; // ambos sanos o ambos heridos: nada que propagar + } + if (!Physics::checkCollision(a, b, 1.0F)) { + continue; + } + // El sano queda herido, propagando el shooter original. + if (A_WOUNDED) { + b.herir(a.getLastHitBy()); + } else { + a.herir(b.getLastHitBy()); + } + } + } + } + void detectShipEnemy(Context& ctx) { constexpr float AMPLIFIER = Defaults::Game::COLLISION_SHIP_ENEMY_AMPLIFIER; @@ -198,6 +228,7 @@ namespace Systems::Collision { void detectAll(Context& ctx) { processWoundedDeaths(ctx); // expiran ANTES de ser tocadas por bala este frame detectBulletEnemy(ctx); + detectWoundedChain(ctx); // un herit pot ferir a un sa al fregar-lo detectShipEnemy(ctx); detectBulletPlayer(ctx); } diff --git a/source/game/systems/collision_system.hpp b/source/game/systems/collision_system.hpp index 8e67400..46c172b 100644 --- a/source/game/systems/collision_system.hpp +++ b/source/game/systems/collision_system.hpp @@ -51,6 +51,12 @@ namespace Systems::Collision { // al `last_hit_by_` del enemy (si está set). void processWoundedDeaths(Context& ctx); + // Si un enemy herido colisiona con uno sano (ni herido ni invulnerable), + // el sano también queda herido (efecto cadena). Propaga `last_hit_by_` para + // que el shooter original siga acreditándose la muerte en cascada. El rebote + // físico ya lo resuelve PhysicsWorld; aquí solo propagamos el estado. + void detectWoundedChain(Context& ctx); + // Detecta colisiones ship → enemy. Si hit, llama on_player_hit(player_id). void detectShipEnemy(Context& ctx);