From 7f51f02d9622d82a01778dfa6acb6d7521cf1414 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Fri, 14 Nov 2025 12:54:59 +0100 Subject: [PATCH] treballant en Player: abans d'entrar a moveOnSlope() --- source/game/entities/player.cpp | 130 ++++++++----------------- source/game/entities/player.hpp | 3 +- source/game/gameplay/collision_map.cpp | 20 ++++ source/game/gameplay/collision_map.hpp | 1 + source/game/gameplay/room.cpp | 5 + source/game/gameplay/room.hpp | 1 + 6 files changed, 67 insertions(+), 93 deletions(-) diff --git a/source/game/entities/player.cpp b/source/game/entities/player.cpp index 89533a20..0dfb3335 100644 --- a/source/game/entities/player.cpp +++ b/source/game/entities/player.cpp @@ -96,33 +96,44 @@ void Player::transitionToState(State state) { switch (state) { case State::ON_GROUND: + std::cout << "ON_GROUND\n"; vy_ = 0; handleDeathByFalling(); jump_sound_ctrl_.reset(); fall_sound_ctrl_.reset(); + current_slope_ = nullptr; break; - case State::ON_SLOPE: + case State::ON_SLOPE: { + std::cout << "ON_SLOPE\n"; vy_ = 0; handleDeathByFalling(); jump_sound_ctrl_.reset(); fall_sound_ctrl_.reset(); + const LineDiagonal* SLOPE_LEFT = room_->getSlopeAtPoint(under_left_foot_); + const LineDiagonal* SLOPE_RIGHT = room_->getSlopeAtPoint(under_right_foot_); + current_slope_ = SLOPE_LEFT ? SLOPE_LEFT : SLOPE_RIGHT; break; + } case State::JUMPING: + std::cout << "JUMPING\n"; // Puede saltar desde ON_GROUND o ON_SLOPE if (previous_state_ == State::ON_GROUND || previous_state_ == State::ON_SLOPE) { vy_ = -MAX_VY; last_grounded_position_ = y_; updateVelocity(); jump_sound_ctrl_.start(); + current_slope_ = nullptr; } break; case State::FALLING: + std::cout << "FALLING\n"; fall_start_position_ = static_cast(y_); last_grounded_position_ = static_cast(y_); vy_ = MAX_VY; vx_ = 0.0F; jump_sound_ctrl_.reset(); fall_sound_ctrl_.start(y_); + current_slope_ = nullptr; break; } } @@ -183,6 +194,7 @@ void Player::moveOnGround(float delta_time) { if (vx_ == 0.0F) { return; } + // Movimiento horizontal y colision con muros const float DISPLACEMENT = vx_ * delta_time; if (vx_ < 0.0F) { const SDL_FRect PROJECTION = getProjection(Direction::LEFT, DISPLACEMENT); @@ -201,6 +213,28 @@ void Player::moveOnGround(float delta_time) { x_ = POS - WIDTH; } } + + // Comprueba colision con rampas, corrige y cambia estado + const int SIDE_X = vx_ < 0.0F ? static_cast(x_) : static_cast(x_) + WIDTH - 1; + const LineVertical SIDE = { + .x = SIDE_X, + .y1 = static_cast(y_) + HEIGHT - 2, + .y2 = static_cast(y_) + HEIGHT - 1}; + + // Comprueba la rampa correspondiente según la dirección + const int SLOPE_Y = vx_ < 0.0F ? room_->checkLeftSlopes(SIDE) : room_->checkRightSlopes(SIDE); + if (SLOPE_Y != Collision::NONE) { + // Hay rampa: sube al jugador para pegarlo a la rampa + // Esta es la nueva posición "ideal" a la que nos queremos teletransportar + const float NEW_Y = SLOPE_Y - HEIGHT; + + // Solo aplicamos el "snap" si es para SUBIR (new_y < y_) + if (NEW_Y < y_) { + y_ = std::max(NEW_Y, y_ - 1.0F); + } + + transitionToState(State::ON_SLOPE); + } } // Movimiento físico del estado ON_SLOPE @@ -210,65 +244,13 @@ void Player::moveOnSlope(float delta_time) { if (vx_ == 0.0F) { return; } - // Movimiento horizontal - const float DISPLACEMENT = vx_ * delta_time; - if (vx_ < 0.0F) { - const SDL_FRect PROJECTION = getProjection(Direction::LEFT, DISPLACEMENT); - const int POS = room_->checkRightSurfaces(PROJECTION); - if (POS == Collision::NONE) { - x_ += DISPLACEMENT; - } else { - x_ = POS + 1; - } - } else if (vx_ > 0.0F) { - const SDL_FRect PROJECTION = getProjection(Direction::RIGHT, DISPLACEMENT); - const int POS = room_->checkLeftSurfaces(PROJECTION); - if (POS == Collision::NONE) { - x_ += DISPLACEMENT; - } else { - x_ = POS - WIDTH; - } - } + // Implementar aqui el desplazamiento en x_ e y_ en funcion de la velocidad y la ecuacion de la recta + // Son LineDiagonal, de 45º. La linea esta en current_slope_ (comprobar que no sea nullptr) - // Movimiento vertical - // Regla: Si está bajando la rampa, se pega a la slope - if (isOnDownSlope()) { - y_ += 1; + if (isOnTopSurface()) { + transitionToState(State::ON_GROUND); return; } - - // Regla: Si está STANDING y tropieza lateralmente con una Slope, se pega a la slope - // Comprueba si hay rampa en contacto lateral (solo los dos pixels inferiores) - const int SIDE_X = vx_ < 0.0F ? static_cast(x_) : static_cast(x_) + WIDTH - 1; - const LineVertical SIDE = { - .x = SIDE_X, - .y1 = static_cast(y_) + HEIGHT - 2, - .y2 = static_cast(y_) + HEIGHT - 1}; - - // Comprueba la rampa correspondiente según la dirección - const int SLOPE_Y = vx_ < 0.0F ? room_->checkLeftSlopes(SIDE) : room_->checkRightSlopes(SIDE); - - if (SLOPE_Y != Collision::NONE) { - // Hay rampa: sube al jugador para pegarlo a la rampa - - // --- INICIO DE LA CORRECCIÓN --- - - // Esta es la nueva posición "ideal" a la que nos queremos teletransportar - const float new_y = SLOPE_Y - HEIGHT; - - // Solo aplicamos el "snap" si es para SUBIR (new_y < y_) - if (new_y < y_) { - // "y_ - 1.0F" es la posición máxima que podemos subir en 1 frame. - // std::max coge la posición más alta (más baja en pantalla): - // - O la posición ideal (new_y) - // - O la posición actual - 1 píxel - // Esto "suaviza" el salto de 2 píxeles (p.ej. 84 -> 82) en dos - // fotogramas (84 -> 83, y luego 83 -> 82) - y_ = std::max(new_y, y_ - 1.0F); - } - - // --- FIN DE LA CORRECCIÓN --- - } } // Movimiento físico del estado JUMPING @@ -404,21 +386,6 @@ void Player::handleBorders() { } } -// Comprueba el estado del jugador -void Player::handleState(float delta_time) { - // Reproduce sonidos según el estado - if (state_ == State::FALLING) { - playFallSound(delta_time); - } else if (state_ == State::ON_GROUND || state_ == State::ON_SLOPE) { - // Si no tiene suelo debajo y no está en rampa descendente -> FALLING - if (!isOnFloor() && !isOnConveyorBelt() && !isOnDownSlope()) { - transitionToState(State::FALLING); // setState() establece vx_=0, vy_=MAX_VY - } - } else if (state_ == State::JUMPING) { - playJumpSound(delta_time); - } -} - // Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla void Player::switchBorders() { switch (border_) { @@ -541,25 +508,6 @@ auto Player::isOnConveyorBelt() -> bool { return on_conveyor_belt; } -// Comprueba si el jugador está sobre una rampa hacia abajo -auto Player::isOnDownSlope() -> bool { - bool on_slope = false; - updateFeet(); - - // Cuando el jugador baja una escalera, se queda volando - // Hay que mirar otro pixel más por debajo - SDL_FPoint left_foot = under_left_foot_; - SDL_FPoint right_foot = under_right_foot_; - left_foot.y += 1.0F; - right_foot.y += 1.0F; - - // Comprueba las rampas - on_slope |= room_->checkLeftSlopes(left_foot); - on_slope |= room_->checkRightSlopes(right_foot); - - return on_slope; -} - // Comprueba si el jugador está sobre una rampa auto Player::isOnSlope() -> bool { bool on_slope = false; diff --git a/source/game/entities/player.hpp b/source/game/entities/player.hpp index 92e359f1..3bb76815 100644 --- a/source/game/entities/player.hpp +++ b/source/game/entities/player.hpp @@ -132,6 +132,7 @@ class Player { std::array collider_points_{}; // Puntos de colisión con el mapa SDL_FPoint under_left_foot_ = {0.0F, 0.0F}; // El punto bajo la esquina inferior izquierda del jugador SDL_FPoint under_right_foot_ = {0.0F, 0.0F}; // El punto bajo la esquina inferior derecha del jugador + const LineDiagonal* current_slope_{nullptr}; // Rampa actual sobe la que está el jugador // --- Variables de juego --- bool is_on_border_ = false; // Indica si el jugador esta en uno de los cuatro bordes de la pantalla @@ -174,7 +175,6 @@ class Player { void handleInput(); // Comprueba las entradas y modifica variables // --- Funciones de gestión de estado --- - void handleState(float delta_time); // Comprueba el estado del jugador y actualiza variables void transitionToState(State state); // Cambia el estado del jugador // --- Funciones de física --- @@ -188,7 +188,6 @@ class Player { auto isOnFloor() -> bool; // Comprueba si el jugador tiene suelo debajo de los pies auto isOnTopSurface() -> bool; // Comprueba si el jugador está sobre una superficie auto isOnConveyorBelt() -> bool; // Comprueba si el jugador esta sobre una cinta transportadora - auto isOnDownSlope() -> bool; // Comprueba si el jugador está sobre una rampa hacia abajo auto isOnSlope() -> bool; // Comprueba si el jugador está sobre una rampa // --- Funciones de actualización de geometría --- diff --git a/source/game/gameplay/collision_map.cpp b/source/game/gameplay/collision_map.cpp index 459cc7f7..5acb10da 100644 --- a/source/game/gameplay/collision_map.cpp +++ b/source/game/gameplay/collision_map.cpp @@ -202,6 +202,26 @@ auto CollisionMap::checkRightSlopes(const SDL_FPoint& p) -> bool { }); } +// Obtiene puntero a slope en un punto (prioriza left_slopes_ sobre right_slopes_) +auto CollisionMap::getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal* { + // Primero busca en rampas izquierdas + for (const auto& slope : left_slopes_) { + if (checkCollision(p, slope)) { + return &slope; + } + } + + // Luego busca en rampas derechas + for (const auto& slope : right_slopes_) { + if (checkCollision(p, slope)) { + return &slope; + } + } + + // No hay colisión con ninguna slope + return nullptr; +} + // === Helpers para recopilar tiles === // Helper: recopila tiles inferiores (muros sin muro debajo) diff --git a/source/game/gameplay/collision_map.hpp b/source/game/gameplay/collision_map.hpp index e17e7416..08814f3d 100644 --- a/source/game/gameplay/collision_map.hpp +++ b/source/game/gameplay/collision_map.hpp @@ -63,6 +63,7 @@ class CollisionMap { auto checkLeftSlopes(const SDL_FPoint& p) -> bool; // Colisión punto con rampas izquierdas auto checkRightSlopes(const LineVertical& line) -> int; // Colisión línea con rampas derechas (retorna Y) auto checkRightSlopes(const SDL_FPoint& p) -> bool; // Colisión punto con rampas derechas + auto getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal*; // Obtiene puntero a slope en un punto // --- Métodos estáticos --- static auto getTileSize() -> int { return TILE_SIZE; } // Tamaño del tile en pixels diff --git a/source/game/gameplay/room.cpp b/source/game/gameplay/room.cpp index f94a62e8..425502ef 100644 --- a/source/game/gameplay/room.cpp +++ b/source/game/gameplay/room.cpp @@ -246,6 +246,11 @@ auto Room::checkRightSlopes(const SDL_FPoint& p) -> bool { return collision_map_->checkRightSlopes(p); } +// Obtiene puntero a slope en un punto +auto Room::getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal* { + return collision_map_->getSlopeAtPoint(p); +} + // Carga las variables desde un fichero de mapa (delegado a RoomLoader) auto Room::loadRoomFile(const std::string& file_path, bool verbose) -> Data { diff --git a/source/game/gameplay/room.hpp b/source/game/gameplay/room.hpp index 1c9419b2..75494d96 100644 --- a/source/game/gameplay/room.hpp +++ b/source/game/gameplay/room.hpp @@ -86,6 +86,7 @@ class Room { auto checkLeftSlopes(const SDL_FPoint& p) -> bool; // Comprueba las colisiones auto checkRightSlopes(const LineVertical& line) -> int; // Comprueba las colisiones auto checkRightSlopes(const SDL_FPoint& p) -> bool; // Comprueba las colisiones + auto getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal*; // Obtiene puntero a slope en un punto void setPaused(bool value); // Pone el mapa en modo pausa [[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; } // Obten la direccion de las superficies automaticas