fixed timer functions

This commit is contained in:
2025-11-23 18:41:52 +01:00
parent d5fdae397d
commit adec55526e
7 changed files with 100 additions and 22 deletions

View File

@ -30,6 +30,9 @@ namespace Config {
constexpr double ARR_RATE = 40.0; // Auto Repeat Rate in ms
constexpr float LEVEL_FADE_DURATION = 3500.0f; // Level background fade time in ms
constexpr int MAX_LEVELS = 20; // Maximum selectable starting level
// Gravity speed multiplier: 1.0 = normal, 2.0 = 2x slower, 0.5 = 2x faster
constexpr double GRAVITY_SPEED_MULTIPLIER = 1;
}
// UI Layout constants

View File

@ -512,6 +512,11 @@ bool ApplicationManager::initializeGame() {
m_game = std::make_unique<Game>(m_startLevelSelection);
// Wire up sound callbacks as main.cpp did
if (m_game) {
// Apply global gravity speed multiplier from config
m_game->setGravityGlobalMultiplier(Config::Gameplay::GRAVITY_SPEED_MULTIPLIER);
// Reset to recalculate gravity with the new multiplier
m_game->reset(m_startLevelSelection);
m_game->setSoundCallback([&](int linesCleared){
SoundEffectManager::instance().playSound("clear_line", 1.0f);
// voice lines handled via asset manager loaded sounds

View File

@ -56,11 +56,53 @@ void Game::reset(int startLevel_) {
_score = 0; _lines = 0; _level = startLevel_; startLevel = startLevel_;
// Initialize gravity using NES timing table (ms per cell by level)
gravityMs = gravityMsForLevel(_level, gravityGlobalMultiplier);
fallAcc = 0; _elapsedSec = 0; gameOver=false; paused=false;
fallAcc = 0; gameOver=false; paused=false;
_startTime = SDL_GetPerformanceCounter();
_pausedTime = 0;
_lastPauseStart = 0;
hold = Piece{}; hold.type = PIECE_COUNT; canHold=true;
refillBag(); spawn();
}
double Game::elapsed() const {
if (!_startTime) return 0.0;
Uint64 currentTime = SDL_GetPerformanceCounter();
Uint64 totalPausedTime = _pausedTime;
// If currently paused, add time since pause started
if (paused && _lastPauseStart > 0) {
totalPausedTime += (currentTime - _lastPauseStart);
}
Uint64 activeTime = currentTime - _startTime - totalPausedTime;
double seconds = (double)activeTime / (double)SDL_GetPerformanceFrequency();
return seconds;
}
void Game::updateElapsedTime() {
// This method is now just for API compatibility
// Actual elapsed time is calculated on-demand in elapsed()
}
void Game::setPaused(bool p) {
if (p == paused) return; // No change
if (p) {
// Pausing - record when pause started
_lastPauseStart = SDL_GetPerformanceCounter();
} else {
// Unpausing - add elapsed pause time to total
if (_lastPauseStart > 0) {
Uint64 currentTime = SDL_GetPerformanceCounter();
_pausedTime += (currentTime - _lastPauseStart);
_lastPauseStart = 0;
}
}
paused = p;
}
void Game::refillBag() {
bag.clear();
for (int i=0;i<PIECE_COUNT;++i) bag.push_back(static_cast<PieceType>(i));
@ -241,13 +283,15 @@ bool Game::tryMoveDown() {
void Game::tickGravity(double frameMs) {
if (paused) return; // Don't tick gravity when paused
// Soft drop: 20x faster for rapid continuous dropping
double effectiveGravityMs = softDropping ? (gravityMs / 5.0) : gravityMs;
fallAcc += frameMs;
while (fallAcc >= gravityMs) {
while (fallAcc >= effectiveGravityMs) {
// Attempt to move down by one row
if (tryMoveDown()) {
// Award soft drop points only if player is actively holding Down
// JS: POINTS.SOFT_DROP = 1 per cell for soft drop
if (softDropping) {
_score += 1;
}
@ -256,13 +300,14 @@ void Game::tickGravity(double frameMs) {
lockPiece();
if (gameOver) break;
}
fallAcc -= gravityMs;
fallAcc -= effectiveGravityMs;
}
}
void Game::softDropBoost(double frameMs) {
// Reduce soft drop speed multiplier from 10.0 to 3.0 to make it less aggressive
if (!paused) fallAcc += frameMs * 3.0;
// This method is now deprecated - soft drop is handled in tickGravity
// Kept for API compatibility but does nothing
(void)frameMs;
}
void Game::hardDrop() {

View File

@ -7,6 +7,7 @@
#include <cstdint>
#include <functional>
#include <memory>
#include <SDL3/SDL.h>
#include "../../core/GravityManager.h"
enum PieceType { I, O, T, S, Z, J, L, PIECE_COUNT };
@ -40,13 +41,14 @@ public:
bool canHoldPiece() const { return canHold; }
bool isGameOver() const { return gameOver; }
bool isPaused() const { return paused; }
void setPaused(bool p) { paused = p; }
void setPaused(bool p);
int score() const { return _score; }
int lines() const { return _lines; }
int level() const { return _level; }
int startLevelBase() const { return startLevel; }
double elapsed() const { return _elapsedSec; }
void addElapsed(double frameMs) { if (!paused) _elapsedSec += frameMs/1000.0; }
double elapsed() const; // Now calculated from start time
void updateElapsedTime(); // Update elapsed time from system clock
bool isSoftDropping() const { return softDropping; }
// Block statistics
const std::array<int, PIECE_COUNT>& getBlockCounts() const { return blockCounts; }
@ -69,6 +71,7 @@ public:
void setGravityGlobalMultiplier(double m) { gravityGlobalMultiplier = m; }
double getGravityGlobalMultiplier() const;
double getGravityMs() const;
double getFallAccumulator() const { return fallAcc; } // Debug: time accumulated toward next drop
void setLevelGravityMultiplier(int level, double m);
private:
@ -85,7 +88,9 @@ private:
int _level{1};
double gravityMs{800.0};
double fallAcc{0.0};
double _elapsedSec{0.0};
Uint64 _startTime{0}; // Performance counter at game start
Uint64 _pausedTime{0}; // Time spent paused (in performance counter ticks)
Uint64 _lastPauseStart{0}; // When the current pause started
bool gameOver{false};
int startLevel{0};
bool softDropping{false}; // true while player holds Down key

View File

@ -412,6 +412,25 @@ void GameRenderer::renderPlayingState(
snprintf(timeStr, sizeof(timeStr), "%02d:%02d", mins, secs);
pixelFont->draw(renderer, scoreX, baseY + 290, timeStr, 0.9f, {255, 255, 255, 255});
// Debug: Gravity timing info
pixelFont->draw(renderer, scoreX, baseY + 330, "GRAVITY", 0.8f, {150, 150, 150, 255});
double gravityMs = game->getGravityMs();
double fallAcc = game->getFallAccumulator();
// Calculate effective gravity (accounting for soft drop)
bool isSoftDrop = game->isSoftDropping();
double effectiveGravityMs = isSoftDrop ? (gravityMs / 2.0) : gravityMs;
double timeUntilDrop = std::max(0.0, effectiveGravityMs - fallAcc);
char gravityStr[32];
snprintf(gravityStr, sizeof(gravityStr), "%.0f ms%s", gravityMs, isSoftDrop ? " (SD)" : "");
pixelFont->draw(renderer, scoreX, baseY + 350, gravityStr, 0.7f, {180, 180, 180, 255});
char dropStr[32];
snprintf(dropStr, sizeof(dropStr), "Drop: %.0f", timeUntilDrop);
SDL_Color dropColor = isSoftDrop ? SDL_Color{255, 200, 100, 255} : SDL_Color{100, 255, 100, 255};
pixelFont->draw(renderer, scoreX, baseY + 370, dropStr, 0.7f, dropColor);
// Gravity HUD
char gms[64];
double gms_val = game->getGravityMs();

View File

@ -33,6 +33,7 @@
#include "audio/MenuWrappers.h"
#include "utils/ImagePathResolver.h"
#include "graphics/renderers/GameRenderer.h"
#include "core/Config.h"
// Debug logging removed: no-op in this build (previously LOG_DEBUG)
@ -629,6 +630,9 @@ int main(int, char **)
}
Game game(startLevelSelection);
// Apply global gravity speed multiplier from config
game.setGravityGlobalMultiplier(Config::Gameplay::GRAVITY_SPEED_MULTIPLIER);
game.reset(startLevelSelection);
// Initialize sound effects system
SoundEffectManager::instance().init();
@ -713,7 +717,7 @@ int main(int, char **)
const double DAS = 170.0, ARR = 40.0;
SDL_Rect logicalVP{0, 0, LOGICAL_W, LOGICAL_H};
float logicalScale = 1.f;
Uint64 lastMs = SDL_GetTicks();
Uint64 lastMs = SDL_GetPerformanceCounter();
bool musicStarted = false;
bool musicLoaded = false;
int currentTrackLoading = 0;
@ -1084,9 +1088,12 @@ int main(int, char **)
}
// --- Timing ---
Uint64 now = SDL_GetTicks();
double frameMs = double(now - lastMs);
Uint64 now = SDL_GetPerformanceCounter();
double frameMs = double(now - lastMs) * 1000.0 / double(SDL_GetPerformanceFrequency());
lastMs = now;
// Cap frame time to avoid spiral of death (max 100ms)
if (frameMs > 100.0) frameMs = 100.0;
const bool *ks = SDL_GetKeyboardState(nullptr);
bool left = state == AppState::Playing && ks[SDL_SCANCODE_LEFT];
bool right = state == AppState::Playing && ks[SDL_SCANCODE_RIGHT];
@ -1132,7 +1139,7 @@ int main(int, char **)
{
if (!game.isPaused()) {
game.tickGravity(frameMs);
game.addElapsed(frameMs);
game.updateElapsedTime();
// Update line effect and clear lines when animation completes
if (lineEffect.isActive()) {

View File

@ -128,16 +128,10 @@ void PlayingState::handleEvent(const SDL_Event& e) {
void PlayingState::update(double frameMs) {
if (!ctx.game) return;
static bool debugPrinted = false;
if (!debugPrinted) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[PLAYING] Starting updates, frameMs=%.2f, paused=%d", frameMs, ctx.game->isPaused());
debugPrinted = true;
}
// forward per-frame gameplay updates (gravity, elapsed)
// forward per-frame gameplay updates (gravity, line effects)
if (!ctx.game->isPaused()) {
ctx.game->tickGravity(frameMs);
ctx.game->addElapsed(frameMs);
ctx.game->updateElapsedTime();
if (ctx.lineEffect && ctx.lineEffect->isActive()) {
if (ctx.lineEffect->update(frameMs / 1000.0f)) {