diff --git a/source/core/defaults/trail.hpp b/source/core/defaults/trail.hpp index d646652..d1d406c 100644 --- a/source/core/defaults/trail.hpp +++ b/source/core/defaults/trail.hpp @@ -11,10 +11,10 @@ namespace Defaults::Trail { constexpr float EMIT_INTERVAL_S = 0.04F; // ~25 Hz nominal constexpr float EMIT_JITTER_S = 0.015F; // ±15 ms al cooldown constexpr float POSITION_JITTER_PX = 2.5F; // jitter al punt de naixement - constexpr float REAR_OFFSET_PX = 10.0F; // distància darrere center_ (cua) + constexpr float REAR_OFFSET_PX = 12.0F; // distància darrere center_ (cua) - constexpr float LIFETIME_BASE_S = 0.65F; - constexpr float LIFETIME_JITTER_S = 0.15F; + constexpr float LIFETIME_BASE_S = 1.3F; + constexpr float LIFETIME_JITTER_S = 0.3F; constexpr float SCALE_MIN = 0.7F; // × estrella starfield (3 px punta) constexpr float SCALE_MAX = 1.2F; @@ -25,11 +25,20 @@ namespace Defaults::Trail { constexpr float PULSE_FREQ_HZ = 2.5F; // Colors del pulse (interpolats sinusoïdalment per partícula) + // P1: groc viu ↔ daurat clàssic constexpr unsigned char COLOR_A_R = 255; constexpr unsigned char COLOR_A_G = 255; - constexpr unsigned char COLOR_A_B = 0; // #FFFF00 — groc viu + constexpr unsigned char COLOR_A_B = 0; // #FFFF00 constexpr unsigned char COLOR_B_R = 218; constexpr unsigned char COLOR_B_G = 165; - constexpr unsigned char COLOR_B_B = 32; // #DAA520 — daurat clàssic + constexpr unsigned char COLOR_B_B = 32; // #DAA520 + + // P2: roig viu ↔ rosa + constexpr unsigned char COLOR_P2_A_R = 255; + constexpr unsigned char COLOR_P2_A_G = 31; + constexpr unsigned char COLOR_P2_A_B = 31; // #FF1F1F + constexpr unsigned char COLOR_P2_B_R = 255; + constexpr unsigned char COLOR_P2_B_G = 105; + constexpr unsigned char COLOR_P2_B_B = 180; // #FF69B4 } // namespace Defaults::Trail diff --git a/source/game/effects/trail_manager.cpp b/source/game/effects/trail_manager.cpp index 25f499f..3ca245d 100644 --- a/source/game/effects/trail_manager.cpp +++ b/source/game/effects/trail_manager.cpp @@ -55,12 +55,12 @@ namespace Effects { } } - for (std::size_t player_id = 0; player_id < ships.size(); player_id++) { - tryEmitFromShip(ships[player_id], player_id, delta_time); + for (std::size_t i = 0; i < ships.size(); i++) { + tryEmitFromShip(ships[i], static_cast(i), delta_time); } } - void TrailManager::tryEmitFromShip(const Ship& ship, std::size_t player_id, float delta_time) { + void TrailManager::tryEmitFromShip(const Ship& ship, std::uint8_t player_id, float delta_time) { if (!ship.isActive()) { emit_cooldown_[player_id] = 0.0F; return; @@ -88,13 +88,13 @@ namespace Effects { .x = CENTER.x - (Defaults::Trail::REAR_OFFSET_PX * COS_F) + JITTER_X, .y = CENTER.y - (Defaults::Trail::REAR_OFFSET_PX * SIN_F) + JITTER_Y}; - emitAt(REAR); + emitAt(REAR, player_id); emit_cooldown_[player_id] = Defaults::Trail::EMIT_INTERVAL_S + randUniform(-Defaults::Trail::EMIT_JITTER_S, Defaults::Trail::EMIT_JITTER_S); } - void TrailManager::emitAt(Vec2 pos) { + void TrailManager::emitAt(Vec2 pos, std::uint8_t player_id) { const int SLOT = findFreeSlot(); if (SLOT < 0) { return; // pool ple — descart silenciós @@ -102,6 +102,7 @@ namespace Effects { Particle& particle = pool_[static_cast(SLOT)]; particle.active = true; + particle.player_id = player_id; particle.origin = pos; particle.phase_x = randUniform(0.0F, TAU); particle.phase_y = randUniform(0.0F, TAU); @@ -146,10 +147,18 @@ namespace Effects { const float MIX = 0.5F + (0.5F * std::sin((TAU * Defaults::Trail::PULSE_FREQ_HZ * time_accumulator_) + particle.phase_pulse)); + const bool IS_P2 = particle.player_id == 1; + const unsigned char A_R = IS_P2 ? Defaults::Trail::COLOR_P2_A_R : Defaults::Trail::COLOR_A_R; + const unsigned char A_G = IS_P2 ? Defaults::Trail::COLOR_P2_A_G : Defaults::Trail::COLOR_A_G; + const unsigned char A_B = IS_P2 ? Defaults::Trail::COLOR_P2_A_B : Defaults::Trail::COLOR_A_B; + const unsigned char B_R = IS_P2 ? Defaults::Trail::COLOR_P2_B_R : Defaults::Trail::COLOR_B_R; + const unsigned char B_G = IS_P2 ? Defaults::Trail::COLOR_P2_B_G : Defaults::Trail::COLOR_B_G; + const unsigned char B_B = IS_P2 ? Defaults::Trail::COLOR_P2_B_B : Defaults::Trail::COLOR_B_B; + const SDL_Color COLOR = { - .r = lerpU8(Defaults::Trail::COLOR_A_R, Defaults::Trail::COLOR_B_R, MIX), - .g = lerpU8(Defaults::Trail::COLOR_A_G, Defaults::Trail::COLOR_B_G, MIX), - .b = lerpU8(Defaults::Trail::COLOR_A_B, Defaults::Trail::COLOR_B_B, MIX), + .r = lerpU8(A_R, B_R, MIX), + .g = lerpU8(A_G, B_G, MIX), + .b = lerpU8(A_B, B_B, MIX), .a = 255}; const float CURRENT_SCALE = particle.scale * FADE; diff --git a/source/game/effects/trail_manager.hpp b/source/game/effects/trail_manager.hpp index 1d2cd7b..aab8d40 100644 --- a/source/game/effects/trail_manager.hpp +++ b/source/game/effects/trail_manager.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include "core/defaults/trail.hpp" @@ -33,8 +34,9 @@ namespace Effects { private: struct Particle { bool active{false}; - Vec2 origin{}; // punt de naixement (no es desplaça) - float phase_x{0.0F}; // fase oscil·lació horitzontal + std::uint8_t player_id{0}; // 0=P1, 1=P2 — selecciona paleta de colors + Vec2 origin{}; // punt de naixement (no es desplaça) + float phase_x{0.0F}; // fase oscil·lació horitzontal float phase_y{0.0F}; float phase_pulse{0.0F}; float age{0.0F}; @@ -42,8 +44,8 @@ namespace Effects { float scale{1.0F}; }; - void tryEmitFromShip(const Ship& ship, std::size_t player_id, float delta_time); - void emitAt(Vec2 pos); + void tryEmitFromShip(const Ship& ship, std::uint8_t player_id, float delta_time); + void emitAt(Vec2 pos, std::uint8_t player_id); auto findFreeSlot() -> int; void drawParticle(const Particle& particle) const;