From d5fdae397dc1f1aa720a6a12722fe31e1155ea85 Mon Sep 17 00:00:00 2001 From: Gregor Klevze Date: Sun, 23 Nov 2025 17:11:37 +0100 Subject: [PATCH] fireworks updated --- src/core/GlobalState.cpp | 117 +++++++++++++++++++++++++++++---------- src/core/GlobalState.h | 2 + 2 files changed, 91 insertions(+), 28 deletions(-) diff --git a/src/core/GlobalState.cpp b/src/core/GlobalState.cpp index 3c74a19..752630e 100644 --- a/src/core/GlobalState.cpp +++ b/src/core/GlobalState.cpp @@ -44,11 +44,19 @@ void GlobalState::shutdown() { void GlobalState::updateFireworks(double frameMs) { const Uint64 currentTime = SDL_GetTicks(); - // Create new fireworks less frequently for subtle background effect - if (currentTime - lastFireworkTime > 1200 + (rand() % 1800)) { // Less frequent: 1200-3000ms - // Spawn across wider area for better coverage - float x = Config::Logical::WIDTH * (0.15f + (rand() % 70) / 100.0f); // 15% - 85% - float y = Config::Logical::HEIGHT * (0.20f + (rand() % 60) / 100.0f); // 20% - 80% + // Check if we have any active fireworks + bool hasActiveFirework = false; + for (const auto& fw : fireworks) { + if (fw.active) { + hasActiveFirework = true; + break; + } + } + + // Only create new firework if no active ones exist + if (!hasActiveFirework && currentTime - lastFireworkTime > 1500 + (rand() % 2000)) { + float x = Config::Logical::WIDTH * (0.15f + (rand() % 70) / 100.0f); + float y = Config::Logical::HEIGHT * (0.20f + (rand() % 60) / 100.0f); createFirework(x, y); lastFireworkTime = currentTime; } @@ -58,25 +66,61 @@ void GlobalState::updateFireworks(double frameMs) { if (!firework.active) continue; bool hasActiveParticles = false; + std::vector newParticles; + newParticles.reserve(20); // Pre-allocate to avoid reallocation + for (auto& particle : firework.particles) { if (particle.life <= 0) continue; - // Update physics (gentler gravity, slight friction) + // Update physics float dt = float(frameMs / 1000.0f); particle.x += particle.vx * dt; particle.y += particle.vy * dt; - particle.vx *= (1.0f - 0.5f * dt); // Less friction for longer travel - particle.vy = particle.vy * (1.0f - 0.2f * dt) + 80.0f * dt; // Gentler gravity + particle.vx *= (1.0f - 0.5f * dt); + particle.vy = particle.vy * (1.0f - 0.2f * dt) + 80.0f * dt; particle.life -= frameMs; - // Smaller particles for subtle effect + // Update size float lifeRatio = particle.life / particle.maxLife; - particle.size = 6.0f + 4.0f * lifeRatio; // Smaller particles + particle.size = (6.0f - particle.generation * 2.0f) + (4.0f - particle.generation) * lifeRatio; + + // Only primary particles create secondary explosions (single cascade level) + if (!particle.hasExploded && particle.generation == 0 && lifeRatio < 0.5f) { + particle.hasExploded = true; + + // Spawn only 3-4 secondary particles + int secondaryCount = 3 + (rand() % 2); + for (int i = 0; i < secondaryCount; ++i) { + BlockParticle secondary; + secondary.x = particle.x; + secondary.y = particle.y; + secondary.generation = 1; // Only one level of cascade + secondary.hasExploded = true; // Don't cascade further + + float angle = (float)(rand() % 360) * 3.14159f / 180.0f; + float speed = 40.0f + (rand() % 40); + secondary.vx = cos(angle) * speed; + secondary.vy = sin(angle) * speed - 20.0f; + + secondary.type = 1 + (rand() % 7); + secondary.maxLife = 700.0f + (rand() % 400); + secondary.life = secondary.maxLife; + secondary.size = 3.0f + (rand() % 2); + + newParticles.push_back(secondary); + } + } if (particle.life > 0) { hasActiveParticles = true; } } + + // Add secondary particles + for (auto& newParticle : newParticles) { + firework.particles.push_back(newParticle); + hasActiveParticles = true; + } firework.active = hasActiveParticles; } @@ -108,6 +152,8 @@ void GlobalState::createFirework(float x, float y) { BlockParticle particle; particle.x = x; particle.y = y; + particle.generation = 0; // Primary explosion + particle.hasExploded = false; // Random velocity in all directions float angle = (float)(rand() % 360) * 3.14159f / 180.0f; @@ -125,7 +171,9 @@ void GlobalState::createFirework(float x, float y) { } void GlobalState::drawFireworks(SDL_Renderer* renderer, SDL_Texture* blocksTex) { - if (!blocksTex) return; + (void)blocksTex; // Not using texture anymore + + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); for (const auto& firework : fireworks) { if (!firework.active) continue; @@ -133,31 +181,44 @@ void GlobalState::drawFireworks(SDL_Renderer* renderer, SDL_Texture* blocksTex) for (const auto& particle : firework.particles) { if (particle.life <= 0) continue; - // Calculate alpha based on remaining life - more transparent for subtle effect + // Calculate alpha based on remaining life float lifeRatio = particle.life / particle.maxLife; - // Reduced opacity: 50% of original for subtle background effect Uint8 alpha = (Uint8)(128 * std::min(1.0f, lifeRatio * 1.6f)); - // Set texture alpha - SDL_SetTextureAlphaMod(blocksTex, alpha); - SDL_SetTextureBlendMode(blocksTex, SDL_BLENDMODE_BLEND); - - // Draw particle as a small block - SDL_FRect srcRect = {(particle.type - 1) * 90.0f, 0, 90.0f, 90.0f}; - SDL_FRect dstRect = { - particle.x - particle.size / 2, - particle.y - particle.size / 2, - particle.size, - particle.size + // Color based on particle type + SDL_Color colors[] = { + {0, 240, 240, alpha}, // Cyan + {240, 160, 0, alpha}, // Orange + {0, 0, 240, alpha}, // Blue + {240, 240, 0, alpha}, // Yellow + {0, 240, 0, alpha}, // Green + {160, 0, 240, alpha}, // Purple + {240, 0, 0, alpha} // Red }; + + SDL_Color color = colors[(particle.type - 1) % 7]; + SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); - SDL_RenderTexture(renderer, blocksTex, &srcRect, &dstRect); + // For small particles, just draw a filled rect (much faster) + if (particle.size <= 4.0f) { + SDL_FRect rect{particle.x - particle.size/2, particle.y - particle.size/2, particle.size, particle.size}; + SDL_RenderFillRect(renderer, &rect); + } else { + // For larger particles, draw a simple circle approximation + float radius = particle.size / 2.0f; + int r = (int)radius; + for (int dy = -r; dy <= r; ++dy) { + int width = (int)sqrt(radius*radius - dy*dy) * 2; + if (width > 0) { + SDL_FRect line{particle.x - width/2.0f, particle.y + dy, (float)width, 1.0f}; + SDL_RenderFillRect(renderer, &line); + } + } + } } } - // Reset texture alpha - SDL_SetTextureAlphaMod(blocksTex, 255); - SDL_SetTextureBlendMode(blocksTex, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); } void GlobalState::resetGameState() { diff --git a/src/core/GlobalState.h b/src/core/GlobalState.h index bd469c0..ce93ff7 100644 --- a/src/core/GlobalState.h +++ b/src/core/GlobalState.h @@ -77,6 +77,8 @@ public: int type; float life, maxLife; float size; + int generation = 0; // 0 = primary, 1 = secondary, 2 = tertiary + bool hasExploded = false; // Track if this particle has spawned children }; struct TetrisFirework {