diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 5c7216e..29da919 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -8,7 +8,8 @@ "Bash(tools/linter/run_cppcheck.sh:*)", "Bash(cat:*)", "Bash(git add:*)", - "Bash(git commit:*)" + "Bash(git commit:*)", + "Bash(git checkout:*)" ], "deny": [], "ask": [] diff --git a/source/game/entities/player.cpp b/source/game/entities/player.cpp index c0b3af2..6c217dc 100644 --- a/source/game/entities/player.cpp +++ b/source/game/entities/player.cpp @@ -55,14 +55,37 @@ void Player::handleInput() { wannaJump = Input::get()->checkAction(InputAction::JUMP); } +// ANTIGUO move() - Comentado durante migración a paradigma de estados +/* void Player::move(float delta_time) { handleHorizontalMovement(delta_time); handleVerticalMovement(delta_time); updateColliderGeometry(); } +*/ + +// NUEVO: La lógica de movimiento está distribuida en move*() y se llama desde update*() +void Player::move(float delta_time) { + // Este método ahora es un dispatcher que llama al método de movimiento correspondiente + switch (state_) { + case State::ON_GROUND: + moveOnGround(delta_time); + break; + case State::ON_SLOPE: + moveOnSlope(delta_time); + break; + case State::JUMPING: + moveJumping(delta_time); + break; + case State::FALLING: + moveFalling(delta_time); + break; + } +} void Player::handleHorizontalMovement(float delta_time) { - if (state_ == State::STANDING) { + // TODO: Verificar si esto debe aplicar solo a ON_GROUND o también ON_SLOPE + if (state_ == State::ON_GROUND || state_ == State::ON_SLOPE) { // Determinama cuál debe ser la velocidad a partir de automovement o de wannaGo updateVelocity(); } @@ -78,7 +101,8 @@ void Player::handleHorizontalMovement(float delta_time) { } void Player::handleVerticalMovement(float delta_time) { - if (state_ == State::STANDING) { + // No hay movimiento vertical en estados terrestres + if (state_ == State::ON_GROUND || state_ == State::ON_SLOPE) { return; } @@ -105,7 +129,8 @@ void Player::handleConveyorBelts() { } void Player::handleShouldFall() { - if (!isOnFloor() and state_ == State::STANDING) { + // TODO: También verificar ON_SLOPE + if (!isOnFloor() and (state_ == State::ON_GROUND || state_ == State::ON_SLOPE)) { transitionToState(State::FALLING); } } @@ -115,14 +140,21 @@ void Player::transitionToState(State state) { state_ = state; switch (state) { - case State::STANDING: + case State::ON_GROUND: + vy_ = 0; + handleDeathByFalling(); + jump_sound_ctrl_.reset(); + fall_sound_ctrl_.reset(); + break; + case State::ON_SLOPE: vy_ = 0; handleDeathByFalling(); jump_sound_ctrl_.reset(); fall_sound_ctrl_.reset(); break; case State::JUMPING: - if (previous_state_ == State::STANDING) { + // 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(); @@ -140,6 +172,29 @@ void Player::transitionToState(State state) { } } +void Player::updateState(float delta_time) { + switch (state_) { + case State::ON_GROUND: + updateOnGround(delta_time); + break; + case State::ON_SLOPE: + updateOnSlope(delta_time); + break; + case State::JUMPING: + updateJumping(delta_time); + break; + case State::FALLING: + updateFalling(delta_time); + break; + } +} + +// ============================================================================ +// NUEVO PARADIGMA: Métodos de actualización por estado +// ============================================================================ + +// ANTIGUO updateState() - Comentado durante migración +/* void Player::updateState(float delta_time) { switch (state_) { case State::STANDING: @@ -160,6 +215,101 @@ void Player::updateState(float delta_time) { break; } } +*/ + +// Actualización lógica del estado ON_GROUND +void Player::updateOnGround(float delta_time) { + (void)delta_time; // No usado en este método, pero se mantiene por consistencia + + // Gestiona las cintas transportadoras + handleConveyorBelts(); + + // Verifica si debe caer (no tiene suelo) + handleShouldFall(); + + // Verifica si el jugador quiere saltar + if (wannaJump) { + transitionToState(State::JUMPING); + } +} + +// 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 + + // Verifica si debe caer (no tiene suelo) + handleShouldFall(); + + // Verifica si el jugador quiere saltar + if (wannaJump) { + transitionToState(State::JUMPING); + } +} + +// Actualización lógica del estado JUMPING +void Player::updateJumping(float delta_time) { + // Desactiva el movimiento automático durante el salto + auto_movement_ = false; + + // Reproduce los sonidos de salto + playJumpSound(delta_time); + + // Verifica si el salto ha terminado (alcanzó la altura inicial) + handleJumpEnd(); +} + +// Actualización lógica del estado FALLING +void Player::updateFalling(float delta_time) { + // Desactiva el movimiento automático durante la caída + auto_movement_ = false; + + // Reproduce los sonidos de caída + playFallSound(delta_time); +} + +// ============================================================================ +// NUEVO PARADIGMA: Métodos de movimiento por estado +// ============================================================================ + +// Movimiento físico del estado ON_GROUND +void Player::moveOnGround(float delta_time) { + // Movimiento horizontal en suelo plano (migrado de handleHorizontalMovement) + handleHorizontalMovement(delta_time); + + // Actualiza geometría de colisión + updateColliderGeometry(); +} + +// Movimiento físico del estado ON_SLOPE +void Player::moveOnSlope(float delta_time) { + // Movimiento horizontal en rampa (migrado de handleHorizontalMovement) + // handleSlopeMovement() ya se llama desde dentro de moveHorizontal() + handleHorizontalMovement(delta_time); + + // Actualiza geometría de colisión + updateColliderGeometry(); +} + +// Movimiento físico del estado JUMPING +void Player::moveJumping(float delta_time) { + // Movimiento horizontal (migrado de handleHorizontalMovement) + handleHorizontalMovement(delta_time); + + // Movimiento vertical (migrado de handleVerticalMovement) + handleVerticalMovement(delta_time); + + // Actualiza geometría de colisión + updateColliderGeometry(); +} + +// Movimiento físico del estado FALLING +void Player::moveFalling(float delta_time) { + // Movimiento vertical (migrado de handleVerticalMovement) + handleVerticalMovement(delta_time); + + // Actualiza geometría de colisión + updateColliderGeometry(); +} // Comprueba si está situado en alguno de los cuatro bordes de la habitación void Player::handleBorders() { @@ -193,7 +343,7 @@ void Player::handleState(float delta_time) { // Reproduce sonidos según el estado if (state_ == State::FALLING) { playFallSound(delta_time); - } else if (state_ == State::STANDING) { + } 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 @@ -208,12 +358,12 @@ void Player::switchBorders() { switch (border_) { case Room::Border::TOP: y_ = PLAY_AREA_BOTTOM - HEIGHT - TILE_SIZE; - transitionToState(State::STANDING); + transitionToState(State::ON_GROUND); // TODO: Detectar si debe ser ON_SLOPE break; case Room::Border::BOTTOM: y_ = PLAY_AREA_TOP; - transitionToState(State::STANDING); + transitionToState(State::ON_GROUND); // TODO: Detectar si debe ser ON_SLOPE break; case Room::Border::RIGHT: @@ -379,7 +529,7 @@ void Player::moveVerticalDown(float delta_time) { 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::STANDING); + transitionToState(State::ON_GROUND); // Aterrizó en superficie plana o conveyor belt } else { // Si no hay colisión con los muros, comprueba la colisión con las rampas // CORRECCIÓN: FALLING siempre se pega a rampas, JUMPING se pega solo si vx_ == 0 @@ -393,7 +543,7 @@ void Player::moveVerticalDown(float delta_time) { // No está saltando y hay colisión con una rampa // Calcula la nueva posición y_ = POINT - HEIGHT; - transitionToState(State::STANDING); + transitionToState(State::ON_SLOPE); // Aterrizó en rampa } else { // No está saltando y no hay colisón con una rampa // Calcula la nueva posición diff --git a/source/game/entities/player.hpp b/source/game/entities/player.hpp index 497d61a..657ea24 100644 --- a/source/game/entities/player.hpp +++ b/source/game/entities/player.hpp @@ -18,7 +18,8 @@ class Player { public: // --- Enums y Structs --- enum class State { - STANDING, + ON_GROUND, // En suelo plano o conveyor belt + ON_SLOPE, // En rampa/pendiente JUMPING, FALLING, }; @@ -41,36 +42,14 @@ class Player { float vx = 0; float vy = 0; int last_grounded_position = 0; - State state = State::STANDING; + State state = State::ON_GROUND; SDL_FlipMode flip = SDL_FLIP_NONE; - - // Constructor por defecto - SpawnData() = default; - - // Constructor con parámetros - SpawnData(float x, float y, float vx, float vy, int last_grounded_position, State state, SDL_FlipMode flip) - : x(x), - y(y), - vx(vx), - vy(vy), - last_grounded_position(last_grounded_position), - state(state), - flip(flip) {} }; struct Data { SpawnData spawn_data; std::string animations_path; std::shared_ptr room = nullptr; - - // Constructor por defecto - Data() = default; - - // Constructor con parámetros - Data(SpawnData spawn_data, const std::string& texture_path, std::string animations_path, std::shared_ptr room) - : spawn_data(spawn_data), - animations_path(std::move(animations_path)), - room(std::move(room)) {} }; struct JumpSoundController { @@ -143,11 +122,11 @@ class Player { bool wannaJump = false; // --- Variables de estado --- - State state_ = State::STANDING; // Estado en el que se encuentra el jugador. Util apara saber si está saltando o cayendo - State previous_state_ = State::STANDING; // Estado previo en el que se encontraba el jugador + State state_ = State::ON_GROUND; // Estado en el que se encuentra el jugador. Util apara saber si está saltando o cayendo + State previous_state_ = State::ON_GROUND; // Estado previo en el que se encontraba el jugador // --- Variables de colisión --- - SDL_FRect collider_box_; // Caja de colisión con los enemigos u objetos + SDL_FRect collider_box_{}; // Caja de colisión con los enemigos u objetos 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 @@ -161,9 +140,9 @@ class Player { int last_grounded_position_ = 0; // Ultima posición en Y en la que se estaba en contacto con el suelo (hace doble función: tracking de caída + altura inicial del salto) // --- Variables de renderizado y sonido --- - Uint8 color_ = 0; // Color del jugador - std::array jumping_sound_; // Array con todos los sonidos del salto - std::array falling_sound_; // Array con todos los sonidos de la caída + Uint8 color_ = 0; // Color del jugador + std::array jumping_sound_{}; // Array con todos los sonidos del salto + std::array falling_sound_{}; // Array con todos los sonidos de la caída JumpSoundController jump_sound_ctrl_; // Controlador de sonidos de salto FallSoundController fall_sound_ctrl_; // Controlador de sonidos de caída int fall_start_position_ = 0; // Posición Y al iniciar la caída @@ -174,6 +153,18 @@ class Player { void handleShouldFall(); void updateState(float delta_time); + // --- Métodos de actualización por estado (nuevo paradigma) --- + void updateOnGround(float delta_time); // Actualización lógica estado ON_GROUND + void updateOnSlope(float delta_time); // Actualización lógica estado ON_SLOPE + void updateJumping(float delta_time); // Actualización lógica estado JUMPING + void updateFalling(float delta_time); // Actualización lógica estado FALLING + + // --- Métodos de movimiento por estado (nuevo paradigma) --- + void moveOnGround(float delta_time); // Movimiento físico estado ON_GROUND + void moveOnSlope(float delta_time); // Movimiento físico estado ON_SLOPE + void moveJumping(float delta_time); // Movimiento físico estado JUMPING + void moveFalling(float delta_time); // Movimiento físico estado FALLING + // --- Funciones de inicialización --- void initSprite(const std::string& animations_path); // Inicializa el sprite del jugador void initSounds(); // Inicializa los sonidos de salto y caida @@ -184,7 +175,7 @@ class Player { // --- Funciones de gestión de estado --- void handleState(float delta_time); // Comprueba el estado del jugador y actualiza variables - void transitionToState(State value); // Cambia el estado del jugador + void transitionToState(State state); // Cambia el estado del jugador // --- Funciones de física --- void applyGravity(float delta_time); // Aplica gravedad al jugador diff --git a/source/game/scenes/game.cpp b/source/game/scenes/game.cpp index d07cf82..a511365 100644 --- a/source/game/scenes/game.cpp +++ b/source/game/scenes/game.cpp @@ -39,10 +39,10 @@ Game::Game(Mode mode) mode_(mode), #ifdef _DEBUG current_room_("03.room"), - spawn_data_(Player::SpawnData(25 * TILE_SIZE, 13 * TILE_SIZE, 0, 0, 0, Player::State::STANDING, SDL_FLIP_HORIZONTAL)) + spawn_data_(Player::SpawnData(25 * TILE_SIZE, 13 * TILE_SIZE, 0, 0, 0, Player::State::ON_GROUND, SDL_FLIP_HORIZONTAL)) #else current_room_("03.room"), - spawn_data_(Player::SpawnData(25 * TILE_SIZE, 13 * TILE_SIZE, 0, 0, 0, Player::State::STANDING, SDL_FLIP_HORIZONTAL)) + spawn_data_(Player::SpawnData(25 * TILE_SIZE, 13 * TILE_SIZE, 0, 0, 0, Player::State::ON_GROUND, SDL_FLIP_HORIZONTAL)) #endif { // Crea objetos e inicializa variables @@ -572,9 +572,8 @@ void Game::checkEndGameCheevos() { // Inicializa al jugador void Game::initPlayer(const Player::SpawnData& spawn_point, std::shared_ptr room) { - std::string player_texture = Options::cheats.alternate_skin == Options::Cheat::State::ENABLED ? "player2.gif" : "player.gif"; std::string player_animations = Options::cheats.alternate_skin == Options::Cheat::State::ENABLED ? "player2.ani" : "player.ani"; - const Player::Data PLAYER(spawn_point, player_texture, player_animations, std::move(room)); + const Player::Data PLAYER{spawn_point, player_animations, std::move(room)}; player_ = std::make_shared(PLAYER); }