diff --git a/data/doors/door1.gif b/data/doors/door1.gif index 2c62eb0..9342d88 100644 Binary files a/data/doors/door1.gif and b/data/doors/door1.gif differ diff --git a/data/doors/door1.yaml b/data/doors/door1.yaml index 858cec1..e42c488 100644 --- a/data/doors/door1.yaml +++ b/data/doors/door1.yaml @@ -1,4 +1,7 @@ # door1 animation +# Hoja de sprites horizontal: 33 frames de 8x32 (264x32 px total). +# Frame 0 = puerta cerrada, frames 1..31 = puerta subiendo pixel a pixel, +# frame 32 = puerta totalmente abierta. tileSetFile: door1.gif frameWidth: 8 frameHeight: 32 @@ -7,10 +10,15 @@ animations: - name: closed frames: [0] + # Apertura: 0.7s con easing easeOutCubic. Cada frame del gif representa + # un pixel de subida; la duración de cada frame se ha precalculado como + # el tiempo que la posición eased está dentro de ese pixel. Resultado: + # arranque rápido (pixels fugaces) y desaceleración progresiva al llegar + # al tope (último pixel se sostiene visiblemente). - name: opening - speed: 0.08 loopFrom: -1 - frames: [1, 2, 3, 4, 5, 6, 7, 8] + speed: [0.0074, 0.0075, 0.0077, 0.0079, 0.0081, 0.0083, 0.0085, 0.0087, 0.0090, 0.0092, 0.0095, 0.0098, 0.0101, 0.0105, 0.0109, 0.0113, 0.0118, 0.0124, 0.0130, 0.0136, 0.0144, 0.0153, 0.0164, 0.0177, 0.0192, 0.0211, 0.0236, 0.0270, 0.0320, 0.0402, 0.0573, 0.2206] + frames: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32] - name: opened - frames: [9] + frames: [32] diff --git a/data/room/04.yaml b/data/room/04.yaml index 5322d7d..0d29537 100644 --- a/data/room/04.yaml +++ b/data/room/04.yaml @@ -32,7 +32,7 @@ tilemap: - [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 269, 269, 269, 269, 269, -1, -1, -1, -1, -1, -1, -1, 24, 25] - [-1, -1, -1, -1, 141, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, 25] - [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 141, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, 25] - - [124, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 7, 7, 7, 50, 25] + - [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 273, 273, 273, 273, 24, 25] # Mapa de colisiones (0 = vacio, 1 = solido) collision: - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] @@ -55,4 +55,4 @@ tilemap: - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1] - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1] - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1] - - [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1] + - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1] diff --git a/source/game/editor/map_editor.cpp b/source/game/editor/map_editor.cpp index 9b71a2d..4d14250 100644 --- a/source/game/editor/map_editor.cpp +++ b/source/game/editor/map_editor.cpp @@ -5,11 +5,13 @@ #include #include -#include // Para std::round -#include // Para std::remove (borrar fichero) -#include // Para ifstream, ofstream -#include // Para cout -#include // Para set +#include // Para std::round +#include // Para std::remove (borrar fichero) +#include // Para directory_iterator (getAnimationCompletions) +#include // Para ifstream, ofstream +#include // Para cout +#include // Para set +#include // Para std::error_code #include "core/input/mouse.hpp" // Para Mouse #include "core/rendering/render_info.hpp" // Para RenderInfo @@ -1350,6 +1352,32 @@ auto MapEditor::getSetCompletions() const -> std::vector { } } +// Devuelve la lista de animaciones disponibles para la entidad seleccionada, +// escaneando la carpeta correspondiente en data/. Cada tipo de entidad solo +// puede usar animaciones de su propio directorio. Para entidades sin animación +// (Item, Room/none) devuelve lista vacía. +auto MapEditor::getAnimationCompletions() const -> std::vector { + const char* folder = nullptr; + switch (selection_.type) { + case EntityType::ENEMY: folder = "data/enemies"; break; + case EntityType::PLATFORM: folder = "data/platforms"; break; + case EntityType::KEY: folder = "data/keys"; break; + case EntityType::DOOR: folder = "data/doors"; break; + default: return {}; + } + std::vector result; + std::error_code ec; + for (const auto& entry : std::filesystem::directory_iterator(folder, ec)) { + if (ec) { break; } + if (!entry.is_regular_file()) { continue; } + const auto& path = entry.path(); + if (path.extension() != ".yaml") { continue; } + result.push_back(toUpper(path.stem().string())); + } + std::sort(result.begin(), result.end()); + return result; +} + // Modifica una propiedad del enemigo seleccionado auto MapEditor::setEnemyProperty(const std::string& property, const std::string& value) -> std::string { // NOLINT(readability-function-cognitive-complexity) if (!active_) { return "Editor not active"; } diff --git a/source/game/editor/map_editor.hpp b/source/game/editor/map_editor.hpp index 422feda..8cdaef7 100644 --- a/source/game/editor/map_editor.hpp +++ b/source/game/editor/map_editor.hpp @@ -63,6 +63,7 @@ class MapEditor { auto duplicateEnemy() -> std::string; [[nodiscard]] auto hasSelectedEnemy() const -> bool { return selection_.is(EntityType::ENEMY); } [[nodiscard]] auto getSetCompletions() const -> std::vector; + [[nodiscard]] auto getAnimationCompletions() const -> std::vector; // Comandos para propiedades de la habitación auto setRoomProperty(const std::string& property, const std::string& value) -> std::string; diff --git a/source/game/entities/player.cpp b/source/game/entities/player.cpp index 3add04c..7d4a543 100644 --- a/source/game/entities/player.cpp +++ b/source/game/entities/player.cpp @@ -238,6 +238,20 @@ void Player::startJump() { void Player::moveHorizontal(float delta_time) { const auto& tc = room_->getTileCollider(); + + // Early exit: si hay pared inmediata en la dirección de movimiento, parar + // y poner vx_=0. Sin esto, el player choca, queda re-posicionado en el + // mismo sitio pero conserva vx_ != 0, así que animate() reproduce walk + // anim continuamente mientras empuja contra la pared. + if (vx_ > 0.0F && tc.checkWallRight(x_, y_, WIDTH, HEIGHT) != Collision::NONE) { + vx_ = 0.0F; + return; + } + if (vx_ < 0.0F && tc.checkWallLeft(x_, y_, WIDTH, HEIGHT) != Collision::NONE) { + vx_ = 0.0F; + return; + } + float new_x = x_ + (vx_ * delta_time); // Comprobar ambos muros siempre (el tilemap extendido incluye paredes de rooms diff --git a/source/game/ui/console_commands.cpp b/source/game/ui/console_commands.cpp index 33b6cb5..8554144 100644 --- a/source/game/ui/console_commands.cpp +++ b/source/game/ui/console_commands.cpp @@ -1043,18 +1043,14 @@ void CommandRegistry::registerHandlers() { // NOLINT(readability-function-cogni dynamic_providers_["SET ITEMCOLOR1"] = color_provider; dynamic_providers_["SET ITEMCOLOR2"] = color_provider; - // SET ANIMATION: animaciones de enemigos (nombres sin extensión, UPPERCASE) + // SET ANIMATION: animaciones disponibles para la entidad seleccionada en + // el editor. La lista la calcula MapEditor escaneando data// del + // tipo de entidad correspondiente. dynamic_providers_["SET ANIMATION"] = []() -> std::vector { - std::vector result; - auto list = Resource::List::get()->getListByType(Resource::List::Type::ANIMATION); - for (const auto& path : list) { - if (path.find("enemies") == std::string::npos) { continue; } - std::string name = getFileName(path); - auto dot = name.rfind('.'); - if (dot != std::string::npos) { name = name.substr(0, dot); } - result.push_back(toUpper(name)); + if (MapEditor::get() != nullptr && MapEditor::get()->isActive()) { + return MapEditor::get()->getAnimationCompletions(); } - return result; + return {}; }; // SET TILESET: tilesets disponibles (nombres sin extensión, UPPERCASE)