minor fixes
This commit is contained in:
@ -55,6 +55,7 @@ void Game::reset(int startLevel_) {
|
||||
// immediately sets up its own level state.
|
||||
std::fill(board.begin(), board.end(), 0);
|
||||
clearAsteroidGrid();
|
||||
recentAsteroidExplosions.clear();
|
||||
std::fill(blockCounts.begin(), blockCounts.end(), 0);
|
||||
bag.clear();
|
||||
_score = 0; _lines = 0; _level = startLevel_; startLevel = startLevel_;
|
||||
@ -164,6 +165,7 @@ void Game::setupChallengeLevel(int level, bool preserveStats) {
|
||||
completedLines.clear();
|
||||
hardDropCells.clear();
|
||||
hardDropFxId = 0;
|
||||
recentAsteroidExplosions.clear();
|
||||
fallAcc = 0.0;
|
||||
gameOver = false;
|
||||
paused = false;
|
||||
@ -548,6 +550,7 @@ void Game::clearCompletedLines() {
|
||||
|
||||
void Game::actualClearLines() {
|
||||
if (completedLines.empty()) return;
|
||||
recentAsteroidExplosions.clear();
|
||||
|
||||
std::array<int, COLS*ROWS> newBoard{};
|
||||
std::array<std::optional<AsteroidCell>, COLS*ROWS> newAst{};
|
||||
|
||||
@ -76,6 +76,8 @@ public:
|
||||
void updateElapsedTime(); // Update elapsed time from system clock
|
||||
bool isSoftDropping() const { return softDropping; }
|
||||
const std::array<std::optional<AsteroidCell>, COLS*ROWS>& asteroidCells() const { return asteroidGrid; }
|
||||
const std::vector<SDL_Point>& getRecentAsteroidExplosions() const { return recentAsteroidExplosions; }
|
||||
void clearRecentAsteroidExplosions() { recentAsteroidExplosions.clear(); }
|
||||
|
||||
// Block statistics
|
||||
const std::array<int, PIECE_COUNT>& getBlockCounts() const { return blockCounts; }
|
||||
@ -181,6 +183,9 @@ private:
|
||||
std::optional<AsteroidType> pendingAsteroidDestroyType;
|
||||
bool asteroidDestroySoundPreplayed{false};
|
||||
|
||||
// Recent asteroid explosion positions (grid coords) for renderer FX
|
||||
std::vector<SDL_Point> recentAsteroidExplosions;
|
||||
|
||||
// Internal helpers ----------------------------------------------------
|
||||
void refillBag();
|
||||
void spawn();
|
||||
|
||||
@ -49,6 +49,31 @@ Starfield3D s_inGridStarfield;
|
||||
bool s_starfieldInitialized = false;
|
||||
std::vector<Sparkle> s_sparkles;
|
||||
float s_sparkleSpawnAcc = 0.0f;
|
||||
|
||||
struct AsteroidBurst {
|
||||
float x;
|
||||
float y;
|
||||
float lifeMs;
|
||||
float maxLifeMs;
|
||||
float baseRadius;
|
||||
SDL_Color color;
|
||||
float spin;
|
||||
};
|
||||
|
||||
std::vector<AsteroidBurst> s_asteroidBursts;
|
||||
|
||||
struct AsteroidShard {
|
||||
float x;
|
||||
float y;
|
||||
float vx;
|
||||
float vy;
|
||||
float lifeMs;
|
||||
float maxLifeMs;
|
||||
float size;
|
||||
SDL_Color color;
|
||||
};
|
||||
|
||||
std::vector<AsteroidShard> s_asteroidShards;
|
||||
}
|
||||
|
||||
struct TransportEffectState {
|
||||
@ -927,6 +952,63 @@ void GameRenderer::renderPlayingState(
|
||||
rowDropOffsets[y] = (lineEffect ? lineEffect->getRowDropOffset(y) : 0.0f);
|
||||
}
|
||||
|
||||
// Spawn glamour bursts for freshly destroyed asteroids
|
||||
if (game) {
|
||||
const auto& bursts = game->getRecentAsteroidExplosions();
|
||||
if (!bursts.empty()) {
|
||||
std::uniform_real_distribution<float> lifeDist(280.0f, 420.0f);
|
||||
std::uniform_real_distribution<float> radiusDist(finalBlockSize * 0.35f, finalBlockSize * 0.7f);
|
||||
std::uniform_real_distribution<float> spinDist(-4.0f, 4.0f);
|
||||
std::uniform_real_distribution<float> shardLife(240.0f, 520.0f);
|
||||
std::uniform_real_distribution<float> shardVX(-0.16f, 0.16f);
|
||||
std::uniform_real_distribution<float> shardVY(-0.22f, -0.06f);
|
||||
std::uniform_real_distribution<float> shardSize(finalBlockSize * 0.06f, finalBlockSize * 0.12f);
|
||||
for (const auto& p : bursts) {
|
||||
if (p.x < 0 || p.x >= Game::COLS || p.y < 0 || p.y >= Game::ROWS) {
|
||||
continue;
|
||||
}
|
||||
float fx = gridX + (static_cast<float>(p.x) + 0.5f) * finalBlockSize;
|
||||
float fy = gridY + (static_cast<float>(p.y) + 0.5f) * finalBlockSize + rowDropOffsets[p.y];
|
||||
|
||||
SDL_Color palette[3] = {
|
||||
SDL_Color{255, 230, 120, 255},
|
||||
SDL_Color{140, 220, 255, 255},
|
||||
SDL_Color{255, 160, 235, 255}
|
||||
};
|
||||
SDL_Color c = palette[s_impactRng() % 3];
|
||||
AsteroidBurst burst{
|
||||
fx,
|
||||
fy,
|
||||
lifeDist(s_impactRng),
|
||||
0.0f,
|
||||
radiusDist(s_impactRng),
|
||||
c,
|
||||
spinDist(s_impactRng)
|
||||
};
|
||||
burst.maxLifeMs = burst.lifeMs;
|
||||
s_asteroidBursts.push_back(burst);
|
||||
|
||||
// Spawn shards for extra sparkle
|
||||
int shardCount = 10 + (s_impactRng() % 8);
|
||||
for (int i = 0; i < shardCount; ++i) {
|
||||
AsteroidShard shard{
|
||||
fx,
|
||||
fy,
|
||||
shardVX(s_impactRng),
|
||||
shardVY(s_impactRng),
|
||||
shardLife(s_impactRng),
|
||||
0.0f,
|
||||
shardSize(s_impactRng),
|
||||
c
|
||||
};
|
||||
shard.maxLifeMs = shard.lifeMs;
|
||||
s_asteroidShards.push_back(shard);
|
||||
}
|
||||
}
|
||||
game->clearRecentAsteroidExplosions();
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the game board
|
||||
const auto &board = game->boardRef();
|
||||
const auto &asteroidCells = game->asteroidCells();
|
||||
@ -1096,6 +1178,75 @@ void GameRenderer::renderPlayingState(
|
||||
}
|
||||
}
|
||||
|
||||
// Update & draw asteroid glamour shards and bursts
|
||||
if (!s_asteroidShards.empty() || !s_asteroidBursts.empty()) {
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_ADD);
|
||||
|
||||
// Shards
|
||||
auto shardIt = s_asteroidShards.begin();
|
||||
while (shardIt != s_asteroidShards.end()) {
|
||||
AsteroidShard& s = *shardIt;
|
||||
s.lifeMs -= sparkDeltaMs;
|
||||
if (s.lifeMs <= 0.0f) {
|
||||
shardIt = s_asteroidShards.erase(shardIt);
|
||||
continue;
|
||||
}
|
||||
s.vy += 0.0007f * sparkDeltaMs;
|
||||
s.x += s.vx * sparkDeltaMs;
|
||||
s.y += s.vy * sparkDeltaMs;
|
||||
float lifeRatio = std::clamp(static_cast<float>(s.lifeMs / s.maxLifeMs), 0.0f, 1.0f);
|
||||
Uint8 alpha = static_cast<Uint8>(lifeRatio * 200.0f);
|
||||
SDL_SetRenderDrawColor(renderer, s.color.r, s.color.g, s.color.b, alpha);
|
||||
float size = s.size * (0.7f + (1.0f - lifeRatio) * 0.8f);
|
||||
SDL_FRect shardRect{
|
||||
s.x - size * 0.5f,
|
||||
s.y - size * 0.5f,
|
||||
size,
|
||||
size * 1.4f
|
||||
};
|
||||
SDL_RenderFillRect(renderer, &shardRect);
|
||||
++shardIt;
|
||||
}
|
||||
|
||||
// Bursts
|
||||
auto it = s_asteroidBursts.begin();
|
||||
while (it != s_asteroidBursts.end()) {
|
||||
AsteroidBurst& b = *it;
|
||||
b.lifeMs -= sparkDeltaMs;
|
||||
if (b.lifeMs <= 0.0f) {
|
||||
it = s_asteroidBursts.erase(it);
|
||||
continue;
|
||||
}
|
||||
float t = 1.0f - static_cast<float>(b.lifeMs / b.maxLifeMs);
|
||||
float alpha = std::clamp(1.0f - t, 0.0f, 1.0f);
|
||||
float radius = b.baseRadius * (1.0f + t * 1.6f);
|
||||
float thickness = std::max(2.0f, radius * 0.25f);
|
||||
float jitter = std::sin(t * 12.0f + b.spin) * 2.0f;
|
||||
|
||||
SDL_Color c = b.color;
|
||||
Uint8 a = static_cast<Uint8>(alpha * 220.0f);
|
||||
SDL_SetRenderDrawColor(renderer, c.r, c.g, c.b, a);
|
||||
SDL_FRect outer{
|
||||
b.x - radius + jitter,
|
||||
b.y - radius + jitter,
|
||||
radius * 2.0f,
|
||||
radius * 2.0f
|
||||
};
|
||||
SDL_RenderRect(renderer, &outer);
|
||||
|
||||
SDL_FRect inner{
|
||||
b.x - (radius - thickness),
|
||||
b.y - (radius - thickness),
|
||||
(radius - thickness) * 2.0f,
|
||||
(radius - thickness) * 2.0f
|
||||
};
|
||||
SDL_SetRenderDrawColor(renderer, 255, 255, 255, static_cast<Uint8>(a * 0.9f));
|
||||
SDL_RenderRect(renderer, &inner);
|
||||
++it;
|
||||
}
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
}
|
||||
|
||||
if (!s_impactSparks.empty()) {
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
auto it = s_impactSparks.begin();
|
||||
|
||||
Reference in New Issue
Block a user