Addes some sparkles

This commit is contained in:
2025-12-07 11:24:32 +01:00
parent 5a95c9180c
commit f5424e8f72

View File

@ -25,6 +25,18 @@ struct ImpactSpark {
SDL_Color color{255, 255, 255, 255};
};
struct Sparkle {
float x = 0.0f;
float y = 0.0f;
float vx = 0.0f;
float vy = 0.0f;
float lifeMs = 0.0f;
float maxLifeMs = 0.0f;
float size = 0.0f;
SDL_Color color{255, 255, 255, 255};
float pulse = 0.0f;
};
struct ActivePieceSmoothState {
uint64_t sequence = 0;
float visualX = 0.0f;
@ -35,6 +47,8 @@ ActivePieceSmoothState s_activePieceSmooth;
Starfield3D s_inGridStarfield;
bool s_starfieldInitialized = false;
std::vector<Sparkle> s_sparkles;
float s_sparkleSpawnAcc = 0.0f;
}
// Color constants (copied from main.cpp)
@ -312,6 +326,121 @@ void GameRenderer::renderPlayingState(
SDL_GetRenderDrawBlendMode(renderer, &oldBlend);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
s_inGridStarfield.draw(renderer, gridX, gridY, 0.22f, true);
// Update and spawn ambient sparkles inside/around the grid
// Use the same RNG and timing values used for impact sparks
if (!game->isPaused()) {
// Spawn rate: ~10 sparks/sec total (adjustable)
const float spawnInterval = 0.08f; // seconds
s_sparkleSpawnAcc += deltaSeconds;
while (s_sparkleSpawnAcc >= spawnInterval) {
s_sparkleSpawnAcc -= spawnInterval;
Sparkle s;
// Choose spawn area: near active piece magnet if present, otherwise along top/border
bool spawnNearPiece = appliedMagnet && (std::uniform_real_distribution<float>(0.0f,1.0f)(s_impactRng) > 0.35f);
float sx = 0.0f, sy = 0.0f;
if (spawnNearPiece) {
// Use starfield magnet target if set (approx center of active piece)
// Random jitter around magnet
float jitterX = std::uniform_real_distribution<float>(-finalBlockSize * 1.2f, finalBlockSize * 1.2f)(s_impactRng);
float jitterY = std::uniform_real_distribution<float>(-finalBlockSize * 1.2f, finalBlockSize * 1.2f)(s_impactRng);
// s_inGridStarfield stores magnet in local coords when used; approximate from magnet calculations above
// We'll center near grid center if magnet not available
sx = std::clamp(GRID_W * 0.5f + jitterX, -finalBlockSize * 2.0f, GRID_W + finalBlockSize * 2.0f);
sy = std::clamp(GRID_H * 0.4f + jitterY, -finalBlockSize * 2.0f, GRID_H + finalBlockSize * 2.0f);
} else {
// Spawn along border: choose side and position
float side = std::uniform_real_distribution<float>(0.0f, 1.0f)(s_impactRng);
// Border band width (how far outside the grid sparks can appear)
const float borderBand = std::max(12.0f, finalBlockSize * 1.0f);
if (side < 0.2f) { // left (outside)
sx = std::uniform_real_distribution<float>(-borderBand, 0.0f)(s_impactRng);
sy = std::uniform_real_distribution<float>(-borderBand, GRID_H + borderBand)(s_impactRng);
} else if (side < 0.4f) { // right (outside)
sx = std::uniform_real_distribution<float>(GRID_W, GRID_W + borderBand)(s_impactRng);
sy = std::uniform_real_distribution<float>(-borderBand, GRID_H + borderBand)(s_impactRng);
} else if (side < 0.6f) { // top (outside)
sx = std::uniform_real_distribution<float>(-borderBand, GRID_W + borderBand)(s_impactRng);
sy = std::uniform_real_distribution<float>(-borderBand, 0.0f)(s_impactRng);
} else if (side < 0.9f) { // top/inside border area
sx = std::uniform_real_distribution<float>(0.0f, GRID_W)(s_impactRng);
sy = std::uniform_real_distribution<float>(0.0f, finalBlockSize * 2.0f)(s_impactRng);
} else { // bottom (outside)
sx = std::uniform_real_distribution<float>(-borderBand, GRID_W + borderBand)(s_impactRng);
sy = std::uniform_real_distribution<float>(GRID_H, GRID_H + borderBand)(s_impactRng);
}
}
s.x = sx;
s.y = sy;
float speed = std::uniform_real_distribution<float>(10.0f, 60.0f)(s_impactRng);
float ang = std::uniform_real_distribution<float>(-3.14159f, 3.14159f)(s_impactRng);
s.vx = std::cos(ang) * speed;
s.vy = std::sin(ang) * speed * 0.25f; // slower vertical movement
s.maxLifeMs = std::uniform_real_distribution<float>(350.0f, 900.0f)(s_impactRng);
s.lifeMs = s.maxLifeMs;
s.size = std::uniform_real_distribution<float>(1.5f, 5.0f)(s_impactRng);
// Soft color range towards warm/cyan tints
if (std::uniform_real_distribution<float>(0.0f,1.0f)(s_impactRng) < 0.5f) {
s.color = SDL_Color{255, 230, 180, 255};
} else {
s.color = SDL_Color{180, 220, 255, 255};
}
s.pulse = std::uniform_real_distribution<float>(0.0f, 6.28f)(s_impactRng);
s_sparkles.push_back(s);
}
}
// Update and draw sparkles
if (!s_sparkles.empty()) {
auto it = s_sparkles.begin();
while (it != s_sparkles.end()) {
Sparkle &sp = *it;
sp.lifeMs -= sparkDeltaMs;
if (sp.lifeMs <= 0.0f) {
// On expiration, spawn a small burst of ImpactSparks (smaller boxes)
const int burstCount = std::uniform_int_distribution<int>(4, 8)(s_impactRng);
for (int bi = 0; bi < burstCount; ++bi) {
ImpactSpark ps;
// Position in absolute coords (same space as other impact sparks)
ps.x = gridX + sp.x + std::uniform_real_distribution<float>(-2.0f, 2.0f)(s_impactRng);
ps.y = gridY + sp.y + std::uniform_real_distribution<float>(-2.0f, 2.0f)(s_impactRng);
float ang = std::uniform_real_distribution<float>(0.0f, 6.2831853f)(s_impactRng);
float speed = std::uniform_real_distribution<float>(10.0f, 120.0f)(s_impactRng);
ps.vx = std::cos(ang) * speed;
ps.vy = std::sin(ang) * speed * 0.8f;
ps.maxLifeMs = std::uniform_real_distribution<float>(220.0f, 500.0f)(s_impactRng);
ps.lifeMs = ps.maxLifeMs;
ps.size = std::max(1.0f, sp.size * 0.5f);
ps.color = sp.color;
s_impactSparks.push_back(ps);
}
it = s_sparkles.erase(it);
continue;
}
float lifeRatio = sp.lifeMs / sp.maxLifeMs;
// simple motion
sp.x += sp.vx * deltaSeconds;
sp.y += sp.vy * deltaSeconds;
sp.vy *= 0.995f; // slight damping
sp.pulse += deltaSeconds * 8.0f;
// Fade and pulse alpha
float pulse = 0.5f + 0.5f * std::sin(sp.pulse);
Uint8 alpha = static_cast<Uint8>(std::clamp(lifeRatio * pulse, 0.0f, 1.0f) * 255.0f);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, sp.color.r, sp.color.g, sp.color.b, alpha);
float half = sp.size * 0.5f;
SDL_FRect fr{gridX + sp.x - half, gridY + sp.y - half, sp.size, sp.size};
SDL_RenderFillRect(renderer, &fr);
++it;
}
}
SDL_SetRenderDrawBlendMode(renderer, oldBlend);
// Draw next piece preview panel border