minor fixes

This commit is contained in:
2025-12-20 20:17:43 +01:00
parent b69b090e45
commit 6c48af0bec
3 changed files with 159 additions and 0 deletions

View File

@ -55,6 +55,7 @@ void Game::reset(int startLevel_) {
// immediately sets up its own level state. // immediately sets up its own level state.
std::fill(board.begin(), board.end(), 0); std::fill(board.begin(), board.end(), 0);
clearAsteroidGrid(); clearAsteroidGrid();
recentAsteroidExplosions.clear();
std::fill(blockCounts.begin(), blockCounts.end(), 0); std::fill(blockCounts.begin(), blockCounts.end(), 0);
bag.clear(); bag.clear();
_score = 0; _lines = 0; _level = startLevel_; startLevel = startLevel_; _score = 0; _lines = 0; _level = startLevel_; startLevel = startLevel_;
@ -164,6 +165,7 @@ void Game::setupChallengeLevel(int level, bool preserveStats) {
completedLines.clear(); completedLines.clear();
hardDropCells.clear(); hardDropCells.clear();
hardDropFxId = 0; hardDropFxId = 0;
recentAsteroidExplosions.clear();
fallAcc = 0.0; fallAcc = 0.0;
gameOver = false; gameOver = false;
paused = false; paused = false;
@ -548,6 +550,7 @@ void Game::clearCompletedLines() {
void Game::actualClearLines() { void Game::actualClearLines() {
if (completedLines.empty()) return; if (completedLines.empty()) return;
recentAsteroidExplosions.clear();
std::array<int, COLS*ROWS> newBoard{}; std::array<int, COLS*ROWS> newBoard{};
std::array<std::optional<AsteroidCell>, COLS*ROWS> newAst{}; std::array<std::optional<AsteroidCell>, COLS*ROWS> newAst{};

View File

@ -76,6 +76,8 @@ public:
void updateElapsedTime(); // Update elapsed time from system clock void updateElapsedTime(); // Update elapsed time from system clock
bool isSoftDropping() const { return softDropping; } bool isSoftDropping() const { return softDropping; }
const std::array<std::optional<AsteroidCell>, COLS*ROWS>& asteroidCells() const { return asteroidGrid; } 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 // Block statistics
const std::array<int, PIECE_COUNT>& getBlockCounts() const { return blockCounts; } const std::array<int, PIECE_COUNT>& getBlockCounts() const { return blockCounts; }
@ -181,6 +183,9 @@ private:
std::optional<AsteroidType> pendingAsteroidDestroyType; std::optional<AsteroidType> pendingAsteroidDestroyType;
bool asteroidDestroySoundPreplayed{false}; bool asteroidDestroySoundPreplayed{false};
// Recent asteroid explosion positions (grid coords) for renderer FX
std::vector<SDL_Point> recentAsteroidExplosions;
// Internal helpers ---------------------------------------------------- // Internal helpers ----------------------------------------------------
void refillBag(); void refillBag();
void spawn(); void spawn();

View File

@ -49,6 +49,31 @@ Starfield3D s_inGridStarfield;
bool s_starfieldInitialized = false; bool s_starfieldInitialized = false;
std::vector<Sparkle> s_sparkles; std::vector<Sparkle> s_sparkles;
float s_sparkleSpawnAcc = 0.0f; 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 { struct TransportEffectState {
@ -927,6 +952,63 @@ void GameRenderer::renderPlayingState(
rowDropOffsets[y] = (lineEffect ? lineEffect->getRowDropOffset(y) : 0.0f); 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 // Draw the game board
const auto &board = game->boardRef(); const auto &board = game->boardRef();
const auto &asteroidCells = game->asteroidCells(); 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()) { if (!s_impactSparks.empty()) {
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
auto it = s_impactSparks.begin(); auto it = s_impactSparks.begin();