diff --git a/source/game/entities/player.cpp b/source/game/entities/player.cpp index 83d8321..17d86cb 100644 --- a/source/game/entities/player.cpp +++ b/source/game/entities/player.cpp @@ -113,16 +113,14 @@ void Player::transitionToState(State state) { //std::cout << "ON_GROUND\n"; vy_ = 0; handleDeathByFalling(); - jump_sound_ctrl_.reset(); - fall_sound_ctrl_.reset(); + resetSoundControllersOnLanding(); current_slope_ = nullptr; break; case State::ON_SLOPE: //std::cout << "ON_SLOPE\n"; vy_ = 0; handleDeathByFalling(); - jump_sound_ctrl_.reset(); - fall_sound_ctrl_.reset(); + resetSoundControllersOnLanding(); updateCurrentSlope(); break; case State::JUMPING: @@ -208,24 +206,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); - 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; - } - } + applyHorizontalMovement(delta_time); // Comprueba colision con rampas, corrige y cambia estado const int SIDE_X = vx_ < 0.0F ? static_cast(x_) : static_cast(x_) + WIDTH - 1; @@ -263,24 +244,7 @@ void Player::moveOnSlope(float delta_time) { const bool IS_LEFT_SLOPE = isLeftSlope(); // Movimiento horizontal con colisión lateral - 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; - } - } + applyHorizontalMovement(delta_time); // Seleccionar el pie apropiado según el tipo de rampa // Left slopes (forma \) colisionan con el pie izquierdo @@ -340,23 +304,7 @@ void Player::moveOnSlope(float delta_time) { // Movimiento físico del estado JUMPING void Player::moveJumping(float delta_time) { // Movimiento horizontal - if (vx_ != 0.0F) { - const float DISPLACEMENT_X = vx_ * delta_time; - const Direction DIRECTION = vx_ > 0.0F ? Direction::RIGHT : Direction::LEFT; - const SDL_FRect PROJECTION = getProjection(DIRECTION, DISPLACEMENT_X); - - // Comprueba la colisión con las superficies - const int POS = DIRECTION == Direction::LEFT ? room_->checkRightSurfaces(PROJECTION) : room_->checkLeftSurfaces(PROJECTION); - - // Calcula la nueva posición - if (POS == Collision::NONE) { - // No hay colisión: mueve al jugador - x_ += DISPLACEMENT_X; - } else { - // Hay colisión: reposiciona al jugador en el punto de colisión - x_ = DIRECTION == Direction::LEFT ? POS + 1 : POS - WIDTH; - } - } + applyHorizontalMovement(delta_time); // Movimiento vertical applyGravity(delta_time); @@ -384,28 +332,16 @@ void Player::moveJumping(float delta_time) { // Crea el rectangulo de proyección en el eje Y para ver si colisiona const SDL_FRect PROJECTION = getProjection(Direction::DOWN, DISPLACEMENT_Y); - // Comprueba la colisión con las superficies y las cintas transportadoras - const float POS = std::max(room_->checkTopSurfaces(PROJECTION), room_->checkAutoSurfaces(PROJECTION)); - if (POS != Collision::NONE) { - // Si hay colisión lo mueve hasta donde no colisiona y pasa a estar sobre la superficie - y_ = POS - HEIGHT; - transitionToState(State::ON_GROUND); // Aterrizó en superficie plana o conveyor belt - } - // Comprueba la colisión con las rampas - else { - // JUMPING colisiona con rampas solo si vx_ == 0 - if (vx_ == 0.0F) { - auto rect = toSDLRect(PROJECTION); - const LineVertical LEFT_SIDE = {.x = rect.x, .y1 = rect.y, .y2 = rect.y + rect.h}; - const LineVertical RIGHT_SIDE = {.x = rect.x + rect.w - 1, .y1 = rect.y, .y2 = rect.y + rect.h}; - const float POINT = std::max(room_->checkRightSlopes(RIGHT_SIDE), room_->checkLeftSlopes(LEFT_SIDE)); - if (POINT != Collision::NONE) { - y_ = POINT - HEIGHT; - transitionToState(State::ON_SLOPE); // Aterrizó en rampa - } else { - // No hay colisón con una rampa - y_ += DISPLACEMENT_Y; - } + // JUMPING colisiona con rampas solo si vx_ == 0 + if (vx_ == 0.0F) { + handleLandingFromAir(DISPLACEMENT_Y, PROJECTION); + } else { + // Comprueba la colisión con las superficies y las cintas transportadoras (sin rampas) + const float POS = std::max(room_->checkTopSurfaces(PROJECTION), room_->checkAutoSurfaces(PROJECTION)); + if (POS != Collision::NONE) { + // Si hay colisión lo mueve hasta donde no colisiona y pasa a estar sobre la superficie + y_ = POS - HEIGHT; + transitionToState(State::ON_GROUND); } else { // Esta saltando con movimiento horizontal y no hay colisión con los muros // Calcula la nueva posición (atraviesa rampas) @@ -421,26 +357,8 @@ void Player::moveFalling(float delta_time) { const float DISPLACEMENT = vy_ * delta_time; const SDL_FRect PROJECTION = getProjection(Direction::DOWN, DISPLACEMENT); - // Comprueba la colisión con las superficies y las cintas transportadoras - const float POS = std::max(room_->checkTopSurfaces(PROJECTION), room_->checkAutoSurfaces(PROJECTION)); - if (POS != Collision::NONE) { - // Si hay colisión lo mueve hasta donde no colisiona y pasa a estar sobre la superficie - y_ = POS - HEIGHT; - transitionToState(State::ON_GROUND); // Aterrizó en superficie plana o conveyor belt - } - // Comprueba la colisión con las rampas - else { - auto rect = toSDLRect(PROJECTION); - const LineVertical LEFT_SIDE = {.x = rect.x, .y1 = rect.y, .y2 = rect.y + rect.h}; - const LineVertical RIGHT_SIDE = {.x = rect.x + rect.w - 1, .y1 = rect.y, .y2 = rect.y + rect.h}; - const float POINT = std::max(room_->checkRightSlopes(RIGHT_SIDE), room_->checkLeftSlopes(LEFT_SIDE)); - if (POINT != Collision::NONE) { - y_ = POINT - HEIGHT; - transitionToState(State::ON_SLOPE); // Aterrizó en rampa - } else { - y_ += DISPLACEMENT; - } - } + // Comprueba aterrizaje en superficies y rampas + handleLandingFromAir(DISPLACEMENT, PROJECTION); } // Comprueba si está situado en alguno de los cuatro bordes de la habitación @@ -869,6 +787,63 @@ void Player::updateVelocity() { } } +// Aplica movimiento horizontal con colisión de muros +void Player::applyHorizontalMovement(float delta_time) { + if (vx_ == 0.0F) { return; } + + 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 { + const SDL_FRect PROJECTION = getProjection(Direction::RIGHT, DISPLACEMENT); + const int POS = room_->checkLeftSurfaces(PROJECTION); + if (POS == Collision::NONE) { + x_ += DISPLACEMENT; + } else { + x_ = POS - WIDTH; + } + } +} + +// Detecta aterrizaje en superficies y rampas +auto Player::handleLandingFromAir(float displacement, const SDL_FRect& projection) -> bool { + // Comprueba la colisión con las superficies y las cintas transportadoras + const float POS = std::max(room_->checkTopSurfaces(projection), room_->checkAutoSurfaces(projection)); + if (POS != Collision::NONE) { + // Si hay colisión lo mueve hasta donde no colisiona y pasa a estar sobre la superficie + y_ = POS - HEIGHT; + transitionToState(State::ON_GROUND); + return true; + } + + // Comprueba la colisión con las rampas + auto rect = toSDLRect(projection); + const LineVertical LEFT_SIDE = {.x = rect.x, .y1 = rect.y, .y2 = rect.y + rect.h}; + const LineVertical RIGHT_SIDE = {.x = rect.x + rect.w - 1, .y1 = rect.y, .y2 = rect.y + rect.h}; + const float POINT = std::max(room_->checkRightSlopes(RIGHT_SIDE), room_->checkLeftSlopes(LEFT_SIDE)); + if (POINT != Collision::NONE) { + y_ = POINT - HEIGHT; + transitionToState(State::ON_SLOPE); + return true; + } + + // No hay colisión + y_ += displacement; + return false; +} + +// Resetea los controladores de sonido al aterrizar +void Player::resetSoundControllersOnLanding() { + jump_sound_ctrl_.reset(); + fall_sound_ctrl_.reset(); +} + // Devuelve el rectangulo de proyeccion auto Player::getProjection(Direction direction, float displacement) -> SDL_FRect { switch (direction) { diff --git a/source/game/entities/player.hpp b/source/game/entities/player.hpp index 8121626..ba8f91c 100644 --- a/source/game/entities/player.hpp +++ b/source/game/entities/player.hpp @@ -181,8 +181,11 @@ class Player { void applyGravity(float delta_time); // Aplica gravedad al jugador // --- Funciones de movimiento y colisión --- - void move(float delta_time); // Orquesta el movimiento del jugador - auto getProjection(Direction direction, float displacement) -> SDL_FRect; // Devuelve el rectangulo de proyeccion + void move(float delta_time); // Orquesta el movimiento del jugador + auto getProjection(Direction direction, float displacement) -> SDL_FRect; // Devuelve el rectangulo de proyeccion + void applyHorizontalMovement(float delta_time); // Aplica movimiento horizontal con colisión de muros + auto handleLandingFromAir(float displacement, const SDL_FRect& projection) -> bool; // Detecta aterrizaje en superficies y rampas + void resetSoundControllersOnLanding(); // Resetea los controladores de sonido al aterrizar // --- Funciones de detección de superficies --- auto isOnFloor() -> bool; // Comprueba si el jugador tiene suelo debajo de los pies