feat: implement textured line clear effects and refine UI alignment
- **Visual Effects**: Upgraded line clear particles to use the game's block texture instead of simple circles, matching the reference web game's aesthetic. - **Particle Physics**: Tuned particle velocity, gravity, and fade rates for a more dynamic explosion effect. - **Rendering Integration**: Updated [main.cpp](cci:7://file:///d:/Sites/Work/tetris/src/main.cpp:0:0-0:0) and `GameRenderer` to pass the block texture to the effect system and correctly trigger animations upon line completion. - **Menu UI**: Fixed [MenuState](cci:1://file:///d:/Sites/Work/tetris/src/states/MenuState.cpp:19:0-19:55) layout calculations to use fixed logical dimensions (1200x1000), ensuring consistent centering and alignment of the logo, buttons, and settings icon across different window sizes. - **Code Cleanup**: Refactored `PlayingState` to delegate effect triggering to the rendering layer where correct screen coordinates are available.
This commit is contained in:
48
src/main.cpp
48
src/main.cpp
@ -17,12 +17,12 @@
|
||||
#include "audio/Audio.h"
|
||||
#include "audio/SoundEffect.h"
|
||||
|
||||
#include "gameplay/Game.h"
|
||||
#include "gameplay/core/Game.h"
|
||||
#include "persistence/Scores.h"
|
||||
#include "graphics/Starfield.h"
|
||||
#include "Starfield3D.h"
|
||||
#include "graphics/Font.h"
|
||||
#include "gameplay/LineEffect.h"
|
||||
#include "graphics/effects/Starfield.h"
|
||||
#include "graphics/effects/Starfield3D.h"
|
||||
#include "graphics/ui/Font.h"
|
||||
#include "gameplay/effects/LineEffect.h"
|
||||
#include "states/State.h"
|
||||
#include "states/LoadingState.h"
|
||||
#include "states/MenuState.h"
|
||||
@ -268,7 +268,7 @@ static void drawSettingsPopup(SDL_Renderer* renderer, FontAtlas& font, bool musi
|
||||
// Starfield now managed by Starfield class
|
||||
|
||||
// State manager integration (scaffolded in StateManager.h)
|
||||
#include "core/StateManager.h"
|
||||
#include "core/state/StateManager.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Intro/Menu state variables
|
||||
@ -664,28 +664,10 @@ int main(int, char **)
|
||||
stateMgr.registerOnEnter(AppState::LevelSelector, [&](){ levelSelectorState->onEnter(); });
|
||||
stateMgr.registerOnExit(AppState::LevelSelector, [&](){ levelSelectorState->onExit(); });
|
||||
|
||||
// Combined Playing state handler: run playingState handler and inline gameplay mapping
|
||||
// Combined Playing state handler: run playingState handler
|
||||
stateMgr.registerHandler(AppState::Playing, [&](const SDL_Event& e){
|
||||
// First give the PlayingState a chance to handle the event
|
||||
playingState->handleEvent(e);
|
||||
|
||||
// Then perform inline gameplay mappings (gravity/rotation/hard-drop/hold)
|
||||
if (e.type == SDL_EVENT_KEY_DOWN && !e.key.repeat) {
|
||||
if (!game.isPaused()) {
|
||||
if (e.key.scancode == SDL_SCANCODE_SPACE) {
|
||||
game.hardDrop();
|
||||
}
|
||||
else if (e.key.scancode == SDL_SCANCODE_UP) {
|
||||
game.rotate(+1);
|
||||
}
|
||||
else if (e.key.scancode == SDL_SCANCODE_Z || (e.key.mod & SDL_KMOD_SHIFT)) {
|
||||
game.rotate(-1);
|
||||
}
|
||||
else if (e.key.scancode == SDL_SCANCODE_C || (e.key.mod & SDL_KMOD_CTRL)) {
|
||||
game.holdCurrent();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
stateMgr.registerOnEnter(AppState::Playing, [&](){ playingState->onEnter(); });
|
||||
stateMgr.registerOnExit(AppState::Playing, [&](){ playingState->onExit(); });
|
||||
@ -983,7 +965,8 @@ int main(int, char **)
|
||||
// Update progress based on background loading
|
||||
if (currentTrackLoading > 0 && !musicLoaded) {
|
||||
currentTrackLoading = Audio::instance().getLoadedTrackCount();
|
||||
if (Audio::instance().isLoadingComplete()) {
|
||||
// If loading is complete OR we've loaded all expected tracks (handles potential thread cleanup hang)
|
||||
if (Audio::instance().isLoadingComplete() || (totalTracks > 0 && currentTrackLoading >= totalTracks)) {
|
||||
Audio::instance().shuffle(); // Shuffle once all tracks are loaded
|
||||
musicLoaded = true;
|
||||
}
|
||||
@ -1006,6 +989,10 @@ int main(int, char **)
|
||||
|
||||
// Ensure we never exceed 100% and reach exactly 100% when everything is loaded
|
||||
loadingProgress = std::min(1.0, loadingProgress);
|
||||
|
||||
// Fix floating point precision issues (0.2 + 0.7 + 0.1 can be 0.9999...)
|
||||
if (loadingProgress > 0.99) loadingProgress = 1.0;
|
||||
|
||||
if (musicLoaded && timeProgress >= 0.1) {
|
||||
loadingProgress = 1.0;
|
||||
}
|
||||
@ -1082,6 +1069,7 @@ int main(int, char **)
|
||||
snprintf(bgPath, sizeof(bgPath), "assets/images/tetris_main_back_level%d.bmp", bgLevel);
|
||||
SDL_Surface* levelBgSurface = SDL_LoadBMP(bgPath);
|
||||
if (levelBgSurface) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Loaded background for level %d: %s", bgLevel, bgPath);
|
||||
nextLevelBackgroundTex = SDL_CreateTextureFromSurface(renderer, levelBgSurface);
|
||||
SDL_DestroySurface(levelBgSurface);
|
||||
// start fade transition
|
||||
@ -1089,6 +1077,7 @@ int main(int, char **)
|
||||
levelFadeElapsed = 0.0f;
|
||||
cachedLevel = bgLevel;
|
||||
} else {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load background for level %d: %s (Error: %s)", bgLevel, bgPath, SDL_GetError());
|
||||
// don't change textures if file missing
|
||||
cachedLevel = -1;
|
||||
}
|
||||
@ -1427,9 +1416,14 @@ int main(int, char **)
|
||||
drawPiece(renderer, blocksTex, game.current(), gridX, gridY, finalBlockSize, false);
|
||||
}
|
||||
|
||||
// Handle line clearing effects
|
||||
if (game.hasCompletedLines() && !lineEffect.isActive()) {
|
||||
lineEffect.startLineClear(game.getCompletedLines(), static_cast<int>(gridX), static_cast<int>(gridY), static_cast<int>(finalBlockSize));
|
||||
}
|
||||
|
||||
// Draw line clearing effects
|
||||
if (lineEffect.isActive()) {
|
||||
lineEffect.render(renderer, static_cast<int>(gridX), static_cast<int>(gridY), static_cast<int>(finalBlockSize));
|
||||
lineEffect.render(renderer, blocksTex, static_cast<int>(gridX), static_cast<int>(gridY), static_cast<int>(finalBlockSize));
|
||||
}
|
||||
|
||||
// Draw next piece preview
|
||||
|
||||
Reference in New Issue
Block a user