Addes some sparkles
This commit is contained in:
@ -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
|
||||
|
||||
Reference in New Issue
Block a user