diff --git a/src/graphics/renderers/SyncLineRenderer.cpp b/src/graphics/renderers/SyncLineRenderer.cpp index 675a735..ddf3153 100644 --- a/src/graphics/renderers/SyncLineRenderer.cpp +++ b/src/graphics/renderers/SyncLineRenderer.cpp @@ -1,11 +1,33 @@ #include "SyncLineRenderer.h" +#include #include +#include SyncLineRenderer::SyncLineRenderer() : m_state(SyncState::Idle), m_flashTimer(0.0f), - m_time(0.0f) {} + m_time(0.0f) { + m_particles.reserve(MAX_PARTICLES); +} + +void SyncLineRenderer::SpawnParticle() { + if (m_particles.size() >= MAX_PARTICLES) { + return; + } + + SyncParticle p; + p.y = m_rect.y + m_rect.h; + p.speed = 120.0f + static_cast(std::rand() % 80); + p.alpha = 180.0f; + m_particles.push_back(p); +} + +void SyncLineRenderer::SpawnBurst(int count) { + for (int i = 0; i < count; ++i) { + SpawnParticle(); + } +} void SyncLineRenderer::SetRect(const SDL_FRect& rect) { m_rect = rect; @@ -20,10 +42,48 @@ void SyncLineRenderer::SetState(SyncState state) { void SyncLineRenderer::TriggerClearFlash() { m_state = SyncState::ClearFlash; m_flashTimer = FLASH_DURATION; + + // Reward burst: strong visual feedback on cooperative clear. + SpawnBurst(20); } void SyncLineRenderer::Update(float deltaTime) { m_time += deltaTime; + m_pulseTime += deltaTime; + + // State-driven particle spawning + float spawnRatePerSec = 0.0f; + switch (m_state) { + case SyncState::LeftReady: + case SyncState::RightReady: + spawnRatePerSec = 3.0f; // slow/occasional + break; + case SyncState::Synced: + spawnRatePerSec = 14.0f; // continuous + break; + default: + spawnRatePerSec = 0.0f; + break; + } + + if (spawnRatePerSec <= 0.0f) { + m_spawnAcc = 0.0f; + } else { + m_spawnAcc += deltaTime * spawnRatePerSec; + while (m_spawnAcc >= 1.0f) { + m_spawnAcc -= 1.0f; + SpawnParticle(); + } + } + + // Update particles + for (auto& p : m_particles) { + p.y -= p.speed * deltaTime; + p.alpha -= 120.0f * deltaTime; + } + std::erase_if(m_particles, [&](const SyncParticle& p) { + return p.y < m_rect.y || p.alpha <= 0.0f; + }); if (m_state == SyncState::ClearFlash) { m_flashTimer -= deltaTime; @@ -58,6 +118,23 @@ void SyncLineRenderer::Render(SDL_Renderer* renderer) { SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + // 1) Pulse wave (Synced only) + if (m_state == SyncState::Synced) { + float wave = std::fmod(m_pulseTime * 2.0f, 1.0f); + float width = 4.0f + wave * 12.0f; + Uint8 alpha = static_cast(120.0f * (1.0f - wave)); + + SDL_FRect waveRect{ + m_rect.x - width * 0.5f, + m_rect.y, + m_rect.w + width, + m_rect.h + }; + + SDL_SetRenderDrawColor(renderer, 100, 255, 120, alpha); + SDL_RenderFillRect(renderer, &waveRect); + } + SDL_Color color = GetBaseColor(); if (m_state == SyncState::Synced) { @@ -65,9 +142,25 @@ void SyncLineRenderer::Render(SDL_Renderer* renderer) { color.a = static_cast(180.0f + pulse * 75.0f); } + // 2) Base SYNC line SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); SDL_RenderFillRect(renderer, &m_rect); + // 3) Energy particles + for (const auto& p : m_particles) { + SDL_FRect dot{ + m_rect.x - 3.0f, + p.y, + m_rect.w + 6.0f, + 3.0f + }; + + Uint8 a = static_cast(std::clamp(p.alpha, 0.0f, 255.0f)); + SDL_SetRenderDrawColor(renderer, 120, 255, 180, a); + SDL_RenderFillRect(renderer, &dot); + } + + // 4) Flash/glow overlay if (m_state == SyncState::ClearFlash) { SDL_FRect glow = m_rect; glow.x -= 3; diff --git a/src/graphics/renderers/SyncLineRenderer.h b/src/graphics/renderers/SyncLineRenderer.h index 3d529d2..f8b1d25 100644 --- a/src/graphics/renderers/SyncLineRenderer.h +++ b/src/graphics/renderers/SyncLineRenderer.h @@ -1,6 +1,8 @@ #pragma once #include +#include + enum class SyncState { Idle, LeftReady, @@ -21,13 +23,27 @@ public: void Render(SDL_Renderer* renderer); private: + struct SyncParticle { + float y; + float speed; + float alpha; + }; + SDL_FRect m_rect{}; SyncState m_state; float m_flashTimer; float m_time; + float m_pulseTime{0.0f}; + float m_spawnAcc{0.0f}; + std::vector m_particles; + static constexpr float FLASH_DURATION = 0.15f; + static constexpr size_t MAX_PARTICLES = 64; + + void SpawnParticle(); + void SpawnBurst(int count); SDL_Color GetBaseColor() const; };