From c1764ba0d844076656aa85e39a06782bc9637c88 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Sat, 11 Apr 2026 19:05:29 +0200 Subject: [PATCH] afinaments --- data/console/commands.yaml | 8 ++------ source/game/entities/player.cpp | 12 ++++++++++++ source/game/entities/player.hpp | 2 ++ source/game/gameplay/solid_actor_manager.cpp | 17 ++++++++++++----- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/data/console/commands.yaml b/data/console/commands.yaml index e132ddd..890bec1 100644 --- a/data/console/commands.yaml +++ b/data/console/commands.yaml @@ -289,18 +289,14 @@ categories: - keyword: CHEAT handler: cmd_cheat description: "Game cheats (GAME only)" - usage: "CHEAT [INFINITE LIVES|INVINCIBILITY|OPEN THE JAIL|CLOSE THE JAIL]" + usage: "CHEAT [INFINITE LIVES|INVINCIBILITY]" hidden: true help_hidden: true completions: - CHEAT: [INFINITE, INVINCIBILITY, OPEN, CLOSE] + CHEAT: [INFINITE, INVINCIBILITY] CHEAT INFINITE: [LIVES] CHEAT INFINITE LIVES: [ON, OFF] CHEAT INVINCIBILITY: [ON, OFF] - CHEAT OPEN: [THE] - CHEAT OPEN THE: [JAIL] - CHEAT CLOSE: [THE] - CHEAT CLOSE THE: [JAIL] debug_extras: hidden: false help_hidden: false diff --git a/source/game/entities/player.cpp b/source/game/entities/player.cpp index b17b582..ee25779 100644 --- a/source/game/entities/player.cpp +++ b/source/game/entities/player.cpp @@ -204,11 +204,22 @@ void Player::updateVelocity(float delta_time) { } } else { if (target != 0.0F) { + // Reset al cambiar de dirección: un giro breve también para en seco. + if (vx_ != 0.0F && ((target > 0.0F) != (vx_ > 0.0F))) { + walk_time_ = 0.0F; + } vx_ = target; + walk_time_ += delta_time; + } else if (walk_time_ < WALK_INERTIA_THRESHOLD) { + // Tap corto: parada seca, sin inercia (permite pasos finos). + vx_ = 0.0F; + walk_time_ = 0.0F; } else if (vx_ > 0.0F) { vx_ = std::max(vx_ - STEP, 0.0F); + if (vx_ == 0.0F) { walk_time_ = 0.0F; } } else if (vx_ < 0.0F) { vx_ = std::min(vx_ + STEP, 0.0F); + if (vx_ == 0.0F) { walk_time_ = 0.0F; } } } } @@ -551,6 +562,7 @@ void Player::transitionToState(State state) { case State::ON_AIR: last_grounded_position_ = static_cast(y_); current_carrier_ = nullptr; // Perder carry al despegar + walk_time_ = 0.0F; // Al aterrizar volverá a contar desde 0 break; } } diff --git a/source/game/entities/player.hpp b/source/game/entities/player.hpp index f1e5366..b4e6a89 100644 --- a/source/game/entities/player.hpp +++ b/source/game/entities/player.hpp @@ -35,6 +35,7 @@ class Player { // --- Constantes de física --- static constexpr float HORIZONTAL_VELOCITY = 75.0F; static constexpr float HORIZONTAL_ACCEL = 500.0F; + static constexpr float WALK_INERTIA_THRESHOLD = 0.16F; static constexpr float MAX_VY = 160.0F; static constexpr float JUMP_VELOCITY = -178.5F; static constexpr float GRAVITY_FORCE = 360.0F; @@ -98,6 +99,7 @@ class Player { float y_ = 0.0F; float vx_ = 0.0F; float vy_ = 0.0F; + float walk_time_ = 0.0F; Direction wanna_go_ = Direction::NONE; bool wanna_jump_ = false; diff --git a/source/game/gameplay/solid_actor_manager.cpp b/source/game/gameplay/solid_actor_manager.cpp index f6a8e20..4a7b8ce 100644 --- a/source/game/gameplay/solid_actor_manager.cpp +++ b/source/game/gameplay/solid_actor_manager.cpp @@ -91,7 +91,11 @@ void SolidActorManager::forEachActor(Fn&& fn) const { // Devuelve el borde derecho del actor bloqueante "a la izquierda" del Player. // Criterio: el AABB del actor solapa el rect del Player y el borde izquierdo // del actor está a la izquierda del borde izquierdo del Player (el Player se -// mete en él por la izquierda). +// mete en él por la izquierda). El test del borde derecho es contact-inclusive +// (>=) para que el contacto flush cuente como pared, igual que TileCollider. +// Sin esto, Player::stuckAgainstWall no detectaba puertas cerradas en contacto +// y la animación "walk" se reproducía aunque el clamp de moveHorizontal +// dejase x_ inmóvil. auto SolidActorManager::checkWallLeft(float px, float py, float pw, float ph) const -> float { float result = Collision::NONE; forEachActor([&](const SolidActor* a, const SDL_FRect& r) { @@ -100,9 +104,10 @@ auto SolidActorManager::checkWallLeft(float px, float py, float pw, float ph) co // Y-overlap if (py + ph <= r.y) { return; } if (py >= r.y + r.h) { return; } - // X-overlap y "a la izquierda": el Player (px) está dentro del actor. + // X-overlap y "a la izquierda": el Player (px) está dentro del actor + // o en contacto exacto con su borde derecho. const float RIGHT_EDGE = r.x + r.w; - if (r.x < px && RIGHT_EDGE > px) { + if (r.x < px && RIGHT_EDGE >= px) { if (result == Collision::NONE || RIGHT_EDGE > result) { result = RIGHT_EDGE; } @@ -112,6 +117,7 @@ auto SolidActorManager::checkWallLeft(float px, float py, float pw, float ph) co } // Devuelve el borde izquierdo del actor bloqueante "a la derecha" del Player. +// Test contact-inclusive (<=) por las mismas razones que checkWallLeft. auto SolidActorManager::checkWallRight(float px, float py, float pw, float ph) const -> float { float result = Collision::NONE; forEachActor([&](const SolidActor* a, const SDL_FRect& r) { @@ -120,9 +126,10 @@ auto SolidActorManager::checkWallRight(float px, float py, float pw, float ph) c // Y-overlap if (py + ph <= r.y) { return; } if (py >= r.y + r.h) { return; } - // X-overlap y "a la derecha": el borde derecho del Player entra en el actor. + // X-overlap y "a la derecha": el borde derecho del Player entra en el + // actor o está en contacto exacto con su borde izquierdo. const float PLAYER_RIGHT = px + pw; - if (r.x < PLAYER_RIGHT && r.x + r.w > PLAYER_RIGHT) { + if (r.x <= PLAYER_RIGHT && r.x + r.w > PLAYER_RIGHT) { if (result == Collision::NONE || r.x < result) { result = r.x; }