Fixed gameplay

This commit is contained in:
2025-12-16 18:51:23 +01:00
parent 29c1d6b745
commit 3264672be0
7 changed files with 355 additions and 180 deletions

View File

@ -398,6 +398,8 @@ static void resetLevelBackgrounds(LevelBackgroundFader& fader) {
// -----------------------------------------------------------------------------
// Intro/Menu state variables
// -----------------------------------------------------------------------------
#include "app/BackgroundManager.h"
#include "app/Fireworks.h"
static double logoAnimCounter = 0.0;
static bool showSettingsPopup = false;
static bool showHelpOverlay = false;
@ -409,176 +411,7 @@ static bool isNewHighScore = false;
static std::string playerName = "";
static bool helpOverlayPausedGame = false;
// -----------------------------------------------------------------------------
// Tetris Block Fireworks for intro animation (block particles)
// Forward declare block render helper used by particles
// Forward declare block render helper used by particles
// (Note: drawBlockTexture implementation was removed, so this is likely dead code unless particles use it.
// However, particles use drawFireworks_impl which uses SDL_RenderGeometry, so this is unused.)
// -----------------------------------------------------------------------------
struct BlockParticle {
float x{}, y{};
float vx{}, vy{};
float size{}, alpha{}, decay{};
float wobblePhase{}, wobbleSpeed{};
float coreHeat{};
BlockParticle(float sx, float sy)
: x(sx), y(sy) {
const float spreadDeg = 35.0f;
const float angleDeg = -90.0f + spreadDeg * ((rand() % 200) / 100.0f - 1.0f); // bias upward
const float angleRad = angleDeg * 3.1415926f / 180.0f;
float speed = 1.3f + (rand() % 220) / 80.0f; // ~1.3..4.05
vx = std::cos(angleRad) * speed * 0.55f;
vy = std::sin(angleRad) * speed;
size = 6.0f + (rand() % 40) / 10.0f; // 6..10 px
alpha = 1.0f;
decay = 0.0095f + (rand() % 180) / 12000.0f; // 0.0095..0.0245
wobblePhase = (rand() % 628) / 100.0f;
wobbleSpeed = 0.08f + (rand() % 60) / 600.0f;
coreHeat = 0.65f + (rand() % 35) / 100.0f;
}
bool update() {
vx *= 0.992f;
vy = vy * 0.985f - 0.015f; // buoyancy pushes upward (negative vy)
x += vx;
y += vy;
wobblePhase += wobbleSpeed;
x += std::sin(wobblePhase) * 0.12f;
alpha -= decay;
size = std::max(1.8f, size - 0.03f);
coreHeat = std::max(0.0f, coreHeat - decay * 0.6f);
return alpha > 0.03f;
}
};
struct TetrisFirework {
std::vector<BlockParticle> particles;
int mode = 0; // 0=random,1=red,2=green,3=palette
TetrisFirework(float x, float y) {
mode = rand() % 4;
int particleCount = 30 + rand() % 25; // 30-55 particles
particles.reserve(particleCount);
for (int i = 0; i < particleCount; ++i) particles.emplace_back(x, y);
}
bool update() {
for (auto it = particles.begin(); it != particles.end();) {
if (!it->update()) it = particles.erase(it); else ++it;
}
return !particles.empty();
}
// Drawing is handled by drawFireworks_impl which accepts the texture to use.
};
static std::vector<TetrisFirework> fireworks;
static Uint64 lastFireworkTime = 0;
// -----------------------------------------------------------------------------
// Fireworks Management
// -----------------------------------------------------------------------------
static void updateFireworks(double frameMs) {
Uint64 now = SDL_GetTicks();
// Randomly spawn new block fireworks (2% chance per frame), bias to lower-right
if (fireworks.size() < 5 && (rand() % 100) < 2) {
float x = LOGICAL_W * 0.55f + float(rand() % int(LOGICAL_W * 0.35f));
float y = LOGICAL_H * 0.80f + float(rand() % int(LOGICAL_H * 0.15f));
fireworks.emplace_back(x, y);
lastFireworkTime = now;
}
// Update existing fireworks
for (auto it = fireworks.begin(); it != fireworks.end();) {
if (!it->update()) {
it = fireworks.erase(it);
} else {
++it;
}
}
}
// Primary implementation that accepts a texture pointer
static SDL_Color blendFireColor(float heat, float alphaScale, Uint8 minG, Uint8 minB) {
heat = std::clamp(heat, 0.0f, 1.0f);
Uint8 r = 255;
Uint8 g = static_cast<Uint8>(std::clamp(120.0f + heat * (255.0f - 120.0f), float(minG), 255.0f));
Uint8 b = static_cast<Uint8>(std::clamp(40.0f + (1.0f - heat) * 60.0f, float(minB), 255.0f));
Uint8 a = static_cast<Uint8>(std::clamp(alphaScale * 255.0f, 0.0f, 255.0f));
return SDL_Color{r, g, b, a};
}
static void drawFireworks_impl(SDL_Renderer* renderer, SDL_Texture*) {
SDL_BlendMode previousBlend = SDL_BLENDMODE_NONE;
SDL_GetRenderDrawBlendMode(renderer, &previousBlend);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_ADD);
static constexpr int quadIndices[6] = {0, 1, 2, 2, 1, 3};
auto makeVertex = [](float px, float py, SDL_Color c) {
SDL_Vertex v{};
v.position.x = px;
v.position.y = py;
v.color = SDL_FColor{
c.r / 255.0f,
c.g / 255.0f,
c.b / 255.0f,
c.a / 255.0f
};
return v;
};
for (auto& f : fireworks) {
for (auto &p : f.particles) {
const float heat = std::clamp(p.alpha * 1.25f + p.coreHeat * 0.5f, 0.0f, 1.0f);
SDL_Color glowColor = blendFireColor(0.45f + heat * 0.55f, p.alpha * 0.55f, 100, 40);
SDL_Color tailBaseColor = blendFireColor(heat * 0.75f, p.alpha * 0.5f, 70, 25);
SDL_Color tailTipColor = blendFireColor(heat * 0.35f, p.alpha * 0.2f, 40, 15);
SDL_Color coreColor = blendFireColor(heat, std::min(1.0f, p.alpha * 1.1f), 150, 80);
float velLen = std::sqrt(p.vx * p.vx + p.vy * p.vy);
SDL_FPoint dir = velLen > 0.001f ? SDL_FPoint{p.vx / velLen, p.vy / velLen}
: SDL_FPoint{0.0f, -1.0f};
SDL_FPoint perp{-dir.y, dir.x};
const float baseWidth = std::max(0.8f, p.size * 0.55f);
const float tipWidth = baseWidth * 0.35f;
const float tailLen = p.size * (3.0f + (1.0f - p.alpha) * 1.8f);
SDL_FPoint base{p.x, p.y};
SDL_FPoint tip{p.x + dir.x * tailLen, p.y + dir.y * tailLen};
SDL_Vertex tailVerts[4];
tailVerts[0] = makeVertex(base.x + perp.x * baseWidth, base.y + perp.y * baseWidth, tailBaseColor);
tailVerts[1] = makeVertex(base.x - perp.x * baseWidth, base.y - perp.y * baseWidth, tailBaseColor);
tailVerts[2] = makeVertex(tip.x + perp.x * tipWidth, tip.y + perp.y * tipWidth, tailTipColor);
tailVerts[3] = makeVertex(tip.x - perp.x * tipWidth, tip.y - perp.y * tipWidth, tailTipColor);
SDL_RenderGeometry(renderer, nullptr, tailVerts, 4, quadIndices, 6);
const float glowAlong = p.size * 0.95f;
const float glowAcross = p.size * 0.6f;
SDL_Vertex glowVerts[4];
glowVerts[0] = makeVertex(base.x + dir.x * glowAlong, base.y + dir.y * glowAlong, glowColor);
glowVerts[1] = makeVertex(base.x - dir.x * glowAlong, base.y - dir.y * glowAlong, glowColor);
glowVerts[2] = makeVertex(base.x + perp.x * glowAcross, base.y + perp.y * glowAcross, glowColor);
glowVerts[3] = makeVertex(base.x - perp.x * glowAcross, base.y - perp.y * glowAcross, glowColor);
SDL_RenderGeometry(renderer, nullptr, glowVerts, 4, quadIndices, 6);
const float coreWidth = p.size * 0.35f;
const float coreHeight = p.size * 0.9f;
SDL_Vertex coreVerts[4];
coreVerts[0] = makeVertex(base.x + perp.x * coreWidth, base.y + perp.y * coreWidth, coreColor);
coreVerts[1] = makeVertex(base.x - perp.x * coreWidth, base.y - perp.y * coreWidth, coreColor);
coreVerts[2] = makeVertex(base.x + dir.x * coreHeight, base.y + dir.y * coreHeight, coreColor);
coreVerts[3] = makeVertex(base.x - dir.x * coreHeight, base.y - dir.y * coreHeight, coreColor);
SDL_RenderGeometry(renderer, nullptr, coreVerts, 4, quadIndices, 6);
}
}
SDL_SetRenderDrawBlendMode(renderer, previousBlend);
}
// External wrappers retained for compatibility; now no-ops to disable the legacy fireworks effect.
void menu_drawFireworks(SDL_Renderer*, SDL_Texture*) {}
void menu_updateFireworks(double) {}
double menu_getLogoAnimCounter() { return logoAnimCounter; }
int menu_getHoveredButton() { return hoveredButton; }
// Fireworks implementation moved to app/Fireworks.{h,cpp}
int main(int, char **)
{
@ -688,8 +521,8 @@ int main(int, char **)
int mainScreenW = 0, mainScreenH = 0;
SDL_Texture* mainScreenTex = nullptr;
// Level background caching system
LevelBackgroundFader levelBackgrounds;
// Level background manager (moved to BackgroundManager)
BackgroundManager levelBackgrounds;
// Default start level selection: 0 (declare here so it's in scope for all handlers)
int startLevelSelection = 0;
@ -1574,7 +1407,7 @@ int main(int, char **)
}
// Advance level background fade if a next texture is queued
updateLevelBackgroundFade(levelBackgrounds, float(frameMs));
levelBackgrounds.update(float(frameMs));
// Update intro animations
if (state == AppState::Menu) {
@ -1690,8 +1523,8 @@ int main(int, char **)
// Draw level-based background for gameplay, starfield for other states
if (state == AppState::Playing) {
int bgLevel = std::clamp(game.level(), 0, 32);
queueLevelBackground(levelBackgrounds, renderer, bgLevel);
renderLevelBackgrounds(levelBackgrounds, renderer, winW, winH, static_cast<float>(gameplayBackgroundClockMs));
levelBackgrounds.queueLevelBackground(renderer, bgLevel);
levelBackgrounds.render(renderer, winW, winH, static_cast<float>(gameplayBackgroundClockMs));
} else if (state == AppState::Loading) {
// Use 3D starfield for loading screen (full screen)
starfield3D.draw(renderer);
@ -2135,7 +1968,7 @@ int main(int, char **)
SDL_DestroyTexture(logoTex);
if (mainScreenTex)
SDL_DestroyTexture(mainScreenTex);
resetLevelBackgrounds(levelBackgrounds);
levelBackgrounds.reset();
if (blocksTex)
SDL_DestroyTexture(blocksTex);
if (scorePanelTex)