From 8893e8f05b80f1605359c40ad32bf231b99861a4 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Fri, 14 Nov 2025 14:11:27 +0100 Subject: [PATCH] casi acabat el Player pero -> canvi de PC --- source/game/entities/player.cpp | 166 +++++++++++++++++++++++++++----- source/game/entities/player.hpp | 2 + 2 files changed, 146 insertions(+), 22 deletions(-) diff --git a/source/game/entities/player.cpp b/source/game/entities/player.cpp index 0dfb3335..a55d06be 100644 --- a/source/game/entities/player.cpp +++ b/source/game/entities/player.cpp @@ -29,6 +29,7 @@ Player::Player(const Data& player) // Pinta el jugador en pantalla void Player::render() { sprite_->render(1, color_); + Screen::get()->getRendererSurface()->putPixel(under_right_foot_.x, under_right_foot_.y, 6); } // Actualiza las variables del objeto @@ -103,17 +104,14 @@ void Player::transitionToState(State state) { 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; + updateCurrentSlope(); break; - } case State::JUMPING: std::cout << "JUMPING\n"; // Puede saltar desde ON_GROUND o ON_SLOPE @@ -167,8 +165,10 @@ void Player::updateOnGround(float delta_time) { // Actualización lógica del estado ON_SLOPE void Player::updateOnSlope(float delta_time) { - (void)delta_time; // No usado en este método, pero se mantiene por consistencia - handleShouldFall(); // Verifica si debe caer (no tiene suelo) + (void)delta_time; // No usado en este método, pero se mantiene por consistencia + + // NOTA: No llamamos handleShouldFall() aquí porque moveOnSlope() ya maneja + // todas las condiciones de salida de la rampa (out of bounds, transición a superficie plana) // Verifica si el jugador quiere saltar if (wannaJump) { transitionToState(State::JUMPING); } @@ -225,14 +225,7 @@ void Player::moveOnGround(float delta_time) { 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); - } - + y_ = SLOPE_Y - HEIGHT; transitionToState(State::ON_SLOPE); } } @@ -244,9 +237,88 @@ void Player::moveOnSlope(float delta_time) { if (vx_ == 0.0F) { return; } - // 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) + // Verificar que tenemos una rampa válida + if (current_slope_ == nullptr) { + transitionToState(State::FALLING); + return; + } + // Determinar el tipo de rampa + 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; + } + } + + // Actualizar posición de los pies para cálculos + updateFeet(); + + // Seleccionar el pie apropiado según el tipo de rampa + // Left slopes (forma \) colisionan con el pie izquierdo + // Right slopes (forma /) colisionan con el pie derecho + const float FOOT_X = IS_LEFT_SLOPE ? under_left_foot_.x : under_right_foot_.x; + + // Calcular la Y del pie basado en la ecuación de la rampa (45 grados) + // Left slope (\): y aumenta con x -> y = y1 + (x - x1) + // Right slope (/): y disminuye con x -> y = y1 - (x - x1) + float foot_y = 0.0F; + if (IS_LEFT_SLOPE) { + foot_y = current_slope_->y1 + (FOOT_X - current_slope_->x1); + } else { + foot_y = current_slope_->y1 - (FOOT_X - current_slope_->x1); + } + + // Ajustar la posición Y del jugador (restar HEIGHT porque foot_y es la posición del pie) + y_ = foot_y - HEIGHT; + + // Verificar si el pie ha salido de los límites horizontales de la rampa + // Usar min/max porque LEFT slopes tienen x1x2 + const int MIN_X = std::min(current_slope_->x1, current_slope_->x2); + const int MAX_X = std::max(current_slope_->x1, current_slope_->x2); + const bool OUT_OF_BOUNDS = (FOOT_X < MIN_X) || (FOOT_X > MAX_X); + + if (OUT_OF_BOUNDS) { + // Determinar si estamos saliendo por arriba o por abajo de la rampa + const bool EXITING_DOWNWARD = (FOOT_X > current_slope_->x2 && IS_LEFT_SLOPE) || + (FOOT_X < current_slope_->x1 && !IS_LEFT_SLOPE); + + if (EXITING_DOWNWARD) { + // Salida por abajo: bajar 1 pixel para ayudar detección de suelo + y_ += 1.0F; + } + // Si sale por arriba, mantener altura (ya está en foot_y - HEIGHT) + + // El jugador ya no está en la rampa, limpiar referencia + current_slope_ = nullptr; + + // Verificar si hay soporte debajo (suelo plano, conveyor belt, u otra slope) + if (isOnFloor()) { + // Hay soporte: transición a ON_GROUND (podría ser superficie, conveyor u otra rampa) + transitionToState(State::ON_GROUND); + } else { + // Sin soporte: empezar a caer + transitionToState(State::FALLING); + } + return; + } + + // Verificar transición a superficie plana if (isOnTopSurface()) { transitionToState(State::ON_GROUND); return; @@ -509,15 +581,65 @@ auto Player::isOnConveyorBelt() -> bool { } // Comprueba si el jugador está sobre una rampa +// Retorna true SOLO si un pie está en rampa Y el otro pie está volando (sin soporte) auto Player::isOnSlope() -> bool { - bool on_slope = false; updateFeet(); - // Comprueba las rampas - on_slope |= room_->checkLeftSlopes(under_left_foot_); - on_slope |= room_->checkRightSlopes(under_right_foot_); + // Verificar qué pie está en qué tipo de rampa + const bool LEFT_FOOT_ON_LEFT_SLOPE = room_->checkLeftSlopes(under_left_foot_); + const bool RIGHT_FOOT_ON_RIGHT_SLOPE = room_->checkRightSlopes(under_right_foot_); - return on_slope; + // Verificar si cada pie está "volando" (sin soporte: ni top surface ni conveyor belt) + const bool LEFT_FOOT_FLYING = !(room_->checkTopSurfaces(under_left_foot_) || + room_->checkConveyorBelts(under_left_foot_)); + const bool RIGHT_FOOT_FLYING = !(room_->checkTopSurfaces(under_right_foot_) || + room_->checkConveyorBelts(under_right_foot_)); + + // Retornar true si UN pie en rampa Y el OTRO volando + return (LEFT_FOOT_ON_LEFT_SLOPE && RIGHT_FOOT_FLYING) || + (RIGHT_FOOT_ON_RIGHT_SLOPE && LEFT_FOOT_FLYING); +} + +// Comprueba si current_slope_ es una rampa izquierda (ascendente a la izquierda) +// Las rampas izquierdas tienen forma \ con x1 < x2 (x aumenta de izq a der) +auto Player::isLeftSlope() -> bool { + if (current_slope_ == nullptr) { + return false; + } + // Left slopes (\): x1 < x2 (x aumenta de izquierda a derecha) + // Right slopes (/): x1 > x2 (x decrece de izquierda a derecha) + return current_slope_->x1 < current_slope_->x2; +} + +// Actualiza current_slope_ con la rampa correcta según el pie que toca +void Player::updateCurrentSlope() { + updateFeet(); + + // Left slopes (\) ascendentes a izquierda tocan el pie izquierdo + if (room_->checkLeftSlopes(under_left_foot_)) { + current_slope_ = room_->getSlopeAtPoint(under_left_foot_); + } + // Right slopes (/) ascendentes a derecha tocan el pie derecho + else if (room_->checkRightSlopes(under_right_foot_)) { + current_slope_ = room_->getSlopeAtPoint(under_right_foot_); + } + // Fallback para casos edge + else { + current_slope_ = room_->getSlopeAtPoint(under_left_foot_); + if (current_slope_ == nullptr) { + current_slope_ = room_->getSlopeAtPoint(under_right_foot_); + } + } + + // Debug output + if (current_slope_ != nullptr) { + const char* TYPE = isLeftSlope() ? "Left \\" : "Right /"; + std::cout << "[SLOPE] " << TYPE + << " from (" << current_slope_->x1 << "," << current_slope_->y1 << ")" + << " to (" << current_slope_->x2 << "," << current_slope_->y2 << ")\n"; + } else { + std::cout << "[SLOPE] nullptr\n"; + } } // Comprueba que el jugador no toque ningun tile de los que matan diff --git a/source/game/entities/player.hpp b/source/game/entities/player.hpp index 3bb76815..81216263 100644 --- a/source/game/entities/player.hpp +++ b/source/game/entities/player.hpp @@ -189,6 +189,8 @@ class Player { auto isOnTopSurface() -> bool; // Comprueba si el jugador está sobre una superficie auto isOnConveyorBelt() -> bool; // Comprueba si el jugador esta sobre una cinta transportadora auto isOnSlope() -> bool; // Comprueba si el jugador está sobre una rampa + auto isLeftSlope() -> bool; // Comprueba si current_slope_ es una rampa izquierda (ascendente a la izquierda) + void updateCurrentSlope(); // Actualiza current_slope_ con la rampa correcta y muestra debug info // --- Funciones de actualización de geometría --- void syncSpriteAndCollider(); // Actualiza collider_box y collision points