#pragma once #include // Para Uint32, SDL_FRect #include // Para shared_ptr, allocator, unique_ptr #include // Para string #include // Para vector #include "animated_sprite.h" // Para AnimatedSprite #include "enter_name.h" // Para EnterName #include "input.h" // Para Input #include "manage_hiscore_table.h" // Para Table #include "scoreboard.h" // Para Scoreboard #include "utils.h" // Para Circle class Texture; // --- Clase Player --- class Player { public: // --- Constantes --- static constexpr int WIDTH = 32; // Anchura static constexpr int HEIGHT = 32; // Altura // --- Id para los jugadores --- enum class Id : int { NO_PLAYER = -1, BOTH_PLAYERS = 0, PLAYER1 = 1, PLAYER2 = 2 }; // --- Estados posibles del jugador --- enum class State { // Estados de movimiento WALKING_LEFT, // Caminando hacia la izquierda WALKING_RIGHT, // Caminando hacia la derecha WALKING_STOP, // Parado, sin moverse // Estados de disparo FIRING_UP, // Disparando hacia arriba FIRING_LEFT, // Disparando hacia la izquierda FIRING_RIGHT, // Disparando hacia la derecha FIRING_NONE, // No está disparando // Estados de retroceso tras disparar RECOILING_UP, // Retroceso tras disparar hacia arriba RECOILING_LEFT, // Retroceso tras disparar hacia la izquierda RECOILING_RIGHT, // Retroceso tras disparar hacia la derecha // Estados de enfriamiento tras disparar COOLING_UP, // Enfriando tras disparar hacia arriba COOLING_LEFT, // Enfriando tras disparar hacia la izquierda COOLING_RIGHT, // Enfriando tras disparar hacia la derecha // Estados generales del jugador PLAYING, // Está jugando activamente CONTINUE, // Cuenta atrás para continuar tras perder CONTINUE_TIME_OUT, // Se ha terminado la cuenta atras para continuar y se retira al jugador de la zona de juego WAITING, // Esperando para entrar a jugar ENTERING_NAME, // Introduciendo nombre para la tabla de puntuaciones SHOWING_NAME, // Mostrando el nombre introducido ROLLING, // El jugador está dando vueltas y rebotando LYING_ON_THE_FLOOR_FOREVER, // El jugador está inconsciente para siempre en el suelo (demo) GAME_OVER, // Fin de la partida, no puede jugar CELEBRATING, // Celebrando victoria (pose de victoria) ENTERING_NAME_GAME_COMPLETED, // Introduciendo nombre tras completar el juego LEAVING_SCREEN, // Saliendo de la pantalla (animación) ENTERING_SCREEN, // Entrando a la pantalla (animación) CREDITS, // Estado para mostrar los créditos del juego TITLE_ANIMATION, // Animacion para el titulo TITLE_HIDDEN, // Animacion para el titulo RESPAWNING, // Tras continuar y volver al juego }; struct Config { Id id; float x; int y; bool demo; SDL_FRect *play_area; // Usamos puntero para mantener la referencia std::vector> texture; std::vector> animations; Table *hi_score_table; // También como puntero para referencia int *glowing_entry; // Puntero para mantener la referencia }; // --- Constructor y destructor --- Player(const Config &config); ~Player() = default; // --- Inicialización y ciclo de vida --- void init(); // Inicializa el jugador void update(); // Actualiza estado, animación y contadores void render(); // Dibuja el jugador en pantalla // --- Entrada y control --- void setInput(Input::Action action); // Procesa entrada general void setInputPlaying(Input::Action action); // Procesa entrada en modo jugando void setInputEnteringName(Input::Action action); // Procesa entrada al introducir nombre // --- Movimiento y animación --- void move(); // Mueve el jugador void setAnimation(); // Establece la animación según el estado // --- Texturas y animaciones --- void setPlayerTextures(const std::vector> &texture); // Cambia las texturas del jugador // --- Estados y contadores --- void updateCooldown(); // Actualiza el cooldown de disparo // --- Puntuación y marcador --- void addScore(int score, int last_hi_score_entry); // Añade puntos void incScoreMultiplier(); // Incrementa el multiplicador void decScoreMultiplier(); // Decrementa el multiplicador // --- Estados de juego --- void setPlayingState(State state); // Cambia el estado de juego void setInvulnerable(bool value); // Establece el valor del estado de invulnerabilidad void setPowerUp(); // Activa el modo PowerUp void updatePowerUp(); // Actualiza el valor de PowerUp void giveExtraHit(); // Concede un toque extra al jugador void removeExtraHit(); // Quita el toque extra al jugador void decContinueCounter(); // Decrementa el contador de continuar // --- Getters y comprobaciones de estado --- [[nodiscard]] auto getRecordNamePos() const -> int; // Obtiene la posición que se está editando del nombre del jugador para la tabla de mejores puntuaciones // Comprobación de playing_state [[nodiscard]] auto isLyingOnTheFloorForever() const -> bool { return playing_state_ == State::LYING_ON_THE_FLOOR_FOREVER; } [[nodiscard]] auto isCelebrating() const -> bool { return playing_state_ == State::CELEBRATING; } [[nodiscard]] auto isContinue() const -> bool { return playing_state_ == State::CONTINUE; } [[nodiscard]] auto isDying() const -> bool { return playing_state_ == State::ROLLING; } [[nodiscard]] auto isEnteringName() const -> bool { return playing_state_ == State::ENTERING_NAME; } [[nodiscard]] auto isShowingName() const -> bool { return playing_state_ == State::SHOWING_NAME; } [[nodiscard]] auto isEnteringNameGameCompleted() const -> bool { return playing_state_ == State::ENTERING_NAME_GAME_COMPLETED; } [[nodiscard]] auto isLeavingScreen() const -> bool { return playing_state_ == State::LEAVING_SCREEN; } [[nodiscard]] auto isGameOver() const -> bool { return playing_state_ == State::GAME_OVER; } [[nodiscard]] auto isPlaying() const -> bool { return playing_state_ == State::PLAYING; } [[nodiscard]] auto isWaiting() const -> bool { return playing_state_ == State::WAITING; } [[nodiscard]] auto isTitleHidden() const -> bool { return playing_state_ == State::TITLE_HIDDEN; } // Getters [[nodiscard]] auto canFire() const -> bool { return cant_fire_counter_ <= 0; } [[nodiscard]] auto hasExtraHit() const -> bool { return extra_hit_; } [[nodiscard]] auto isCooling() const -> bool { return firing_state_ == State::COOLING_LEFT || firing_state_ == State::COOLING_UP || firing_state_ == State::COOLING_RIGHT; } [[nodiscard]] auto isRecoiling() const -> bool { return firing_state_ == State::RECOILING_LEFT || firing_state_ == State::RECOILING_UP || firing_state_ == State::RECOILING_RIGHT; } [[nodiscard]] auto qualifiesForHighScore() const -> bool { return qualifies_for_high_score_; } [[nodiscard]] auto isInvulnerable() const -> bool { return invulnerable_; } [[nodiscard]] auto isPowerUp() const -> bool { return power_up_; } auto getCollider() -> Circle & { return collider_; } [[nodiscard]] auto getScoreMultiplier() const -> float { return score_multiplier_; } [[nodiscard]] auto getCoffees() const -> int { return coffees_; } [[nodiscard]] auto getContinueCounter() const -> int { return continue_counter_; } [[nodiscard]] auto getController() const -> int { return controller_index_; } [[nodiscard]] static auto getHeight() -> int { return HEIGHT; } [[nodiscard]] auto getId() const -> Player::Id { return id_; } [[nodiscard]] auto getInvulnerableCounter() const -> int { return invulnerable_counter_; } [[nodiscard]] auto getPosX() const -> int { return static_cast(pos_x_); } [[nodiscard]] auto getPosY() const -> int { return pos_y_; } [[nodiscard]] auto getPowerUpCounter() const -> int { return power_up_counter_; } [[nodiscard]] auto getRecordName() const -> std::string { return enter_name_ ? enter_name_->getFinalName() : "xxx"; } [[nodiscard]] auto getLastEnterName() const -> std::string { return last_enter_name_; } [[nodiscard]] auto getScore() const -> int { return score_; } [[nodiscard]] auto getScoreBoardPanel() const -> Scoreboard::Id { return scoreboard_panel_; } [[nodiscard]] static auto getWidth() -> int { return WIDTH; } [[nodiscard]] auto getPlayingState() const -> State { return playing_state_; } [[nodiscard]] auto getName() const -> const std::string & { return name_; } [[nodiscard]] auto get1CC() const -> bool { return game_completed_ && credits_used_ == 1; } [[nodiscard]] auto getEnterNamePositionOverflow() const -> bool { return enter_name_ ? enter_name_->getPositionOverflow() : false; } // Setters inline void setController(int index) { controller_index_ = index; } void setCantFireCounter(int counter) { recoiling_state_duration_ = cant_fire_counter_ = counter; } void setFiringState(State state) { firing_state_ = state; } void setInvulnerableCounter(int value) { invulnerable_counter_ = value; } void setName(const std::string &name) { name_ = name; } void setPowerUpCounter(int value) { power_up_counter_ = value; } void setScore(int score) { score_ = score; } void setScoreBoardPanel(Scoreboard::Id panel) { scoreboard_panel_ = panel; } void setScoreMultiplier(float value) { score_multiplier_ = value; } void setWalkingState(State state) { walking_state_ = state; } void addCredit() { ++credits_used_; } void setGamepad(std::shared_ptr gamepad) { gamepad_ = gamepad; } [[nodiscard]] auto getGamepad() const -> std::shared_ptr { return gamepad_; } void setUsesKeyboard(bool value) { uses_keyboard_ = value; } [[nodiscard]] auto getUsesKeyboard() const -> bool { return uses_keyboard_; } void setHiScoreTable(const Table &table) { hi_score_table_ = table; } [[nodiscard]] auto getHiScoreTable() const -> const Table & { return hi_score_table_; } void setGlowingEntry(const int &entry) { glowing_entry_ = entry; } private: // --- Constantes --- static constexpr int POWERUP_COUNTER = 1500; // Duración del estado PowerUp static constexpr int INVULNERABLE_COUNTER = 200; // Duración del estado invulnerable static constexpr float BASE_SPEED = 1.5F; // Velocidad base del jugador static constexpr int COOLING_DURATION = 50; static constexpr int COOLING_COMPLETE = 0; static constexpr int WAITING_COUNTER = 1000; // --- Objetos y punteros --- std::unique_ptr player_sprite_; // Sprite para dibujar el jugador std::unique_ptr power_sprite_; // Sprite para dibujar el aura del jugador con el poder a tope std::unique_ptr enter_name_; // Clase utilizada para introducir el nombre std::shared_ptr gamepad_ = nullptr; // Dispositivo asociado Table &hi_score_table_; // Tabla de máximas puntuaciones int &glowing_entry_; // Entrada de la tabla de puntuaciones para hacerla brillar std::string name_; // Nombre del jugador std::string last_enter_name_; // Último nombre introducido en la tabla de puntuaciones // --- Estructuras y enums --- SDL_FRect play_area_; // Rectángulo con la zona de juego Circle collider_ = Circle(0, 0, 9); // Círculo de colisión del jugador Scoreboard::Id scoreboard_panel_ = Scoreboard::Id::LEFT; // Panel del marcador asociado al jugador Id id_; // Identificador para el jugador State walking_state_ = State::WALKING_STOP; // Estado del jugador al moverse State firing_state_ = State::FIRING_NONE; // Estado del jugador al disparar State playing_state_ = State::WAITING; // Estado del jugador en el juego // --- Variables float --- float pos_x_ = 0.0F; // Posición en el eje X float default_pos_x_; // Posición inicial para el jugador float vel_x_ = 0.0F; // Cantidad de píxeles a desplazarse en el eje X float score_multiplier_ = 1.0F; // Multiplicador de puntos // --- Variables int --- int pos_y_ = 0; // Posición en el eje Y int default_pos_y_; // Posición inicial para el jugador int vel_y_ = 0; // Cantidad de píxeles a desplazarse en el eje Y int cant_fire_counter_ = 0; // Contador durante el cual no puede disparar int recoiling_state_counter_ = 0; // Contador para la animación del estado de retroceso int recoiling_state_duration_ = 0; // Número de frames que dura el estado de retroceso int cooling_state_counter_ = 0; // Contador para la animación del estado cooling int invulnerable_counter_ = INVULNERABLE_COUNTER; // Contador para la invulnerabilidad int score_ = 0; // Puntos del jugador int coffees_ = 0; // Indica cuántos cafés lleva acumulados int power_up_counter_ = POWERUP_COUNTER; // Temporizador para el modo PowerUp int power_up_x_offset_ = 0; // Desplazamiento del sprite de PowerUp respecto al sprite del jugador int continue_counter_ = 10; // Contador para poder continuar int controller_index_ = 0; // Índice del array de mandos que utilizará para moverse int name_entry_idle_counter_ = 0; // Contador para poner nombre int name_entry_total_counter_ = 0; // Segundos totales que lleva acumulados poniendo nombre int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente int credits_used_ = 0; // Indica el número de veces que ha continuado int waiting_counter_ = 0; // Contador para el estado de espera // --- Variables Uint32 --- Uint32 continue_ticks_ = 0; // Variable para poder cambiar el contador de continue en función del tiempo Uint32 name_entry_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo Uint32 showing_name_ticks_ = 0; // Tiempo en el que se entra al estado SHOWING_NAME // --- Flags booleanas --- bool qualifies_for_high_score_ = false; // Indica si tiene una puntuación que le permite entrar en la tabla de records bool invulnerable_ = true; // Indica si el jugador es invulnerable bool extra_hit_ = false; // Indica si el jugador tiene un toque extra bool power_up_ = false; // Indica si el jugador tiene activo el modo PowerUp bool demo_ = false; // Para que el jugador sepa si está en el modo demostración bool game_completed_ = false; // Indica si ha completado el juego bool uses_keyboard_ = false; // Indica si usa el teclado como dispositivo de control // --- Métodos internos --- void shiftColliders(); // Actualiza el círculo de colisión a la posición del jugador void shiftSprite(); // Recoloca el sprite void updateInvulnerable(); // Monitoriza el estado de invulnerabilidad void updateContinueCounter(); // Actualiza el contador de continue void updateEnterNameCounter(); // Actualiza el contador de entrar nombre void updateShowingName(); // Actualiza el estado SHOWING_NAME void decNameEntryCounter(); // Decrementa el contador de entrar nombre void updateScoreboard(); // Actualiza el panel del marcador void setScoreboardMode(Scoreboard::Mode mode) const; // Cambia el modo del marcador void playSound(const std::string &name) const; // Hace sonar un sonido [[nodiscard]] auto isRenderable() const -> bool; // Indica si se puede dibujar el objeto void addScoreToScoreBoard() const; // Añade una puntuación a la tabla de records void handleFiringCooldown(); // Gestiona el tiempo de espera después de disparar antes de permitir otro disparo void handleRecoilAndCooling(); // Procesa simultáneamente el retroceso del arma y la transición al estado de enfriamiento si aplica void handleCoolingState(); // Actualiza la lógica interna mientras el sistema está en estado de enfriamiento void transitionToRecoiling(); // Cambia el estado actual al de retroceso después de disparar void transitionToCooling(); // Cambia el estado actual al de enfriamiento (por ejemplo, tras una ráfaga o sobrecalentamiento) void completeCooling(); // Finaliza el proceso de enfriamiento y restablece el estado listo para disparar void handlePlayingMovement(); // Gestiona el movimiento del personaje u objeto durante el estado de juego activo void handleRollingMovement(); // Actualiza la lógica de movimiento de "rodar" (posiblemente tras impacto o acción especial) void handleRollingBoundaryCollision(); // Detecta y maneja colisiones del objeto rodante con los límites de la pantalla void handleRollingGroundCollision(); // Gestiona la interacción del objeto rodante con el suelo (rebotes, frenado, etc.) void handleRollingStop(); // Detiene el movimiento del objeto rodante cuando se cumplen las condiciones necesarias void handleRollingBounce(); // Aplica una lógica de rebote al colisionar con superficies durante el rodamiento void handleTitleAnimation(); // Ejecuta la animación del título en pantalla (ej. entrada, parpadeo o desplazamiento) void handleContinueTimeOut(); // Gestiona el tiempo de espera en la pantalla de "Continuar" y decide si pasar a otro estado void handleLeavingScreen(); // Lógica para salir de la pantalla actual (transición visual o cambio de escena) void handleEnteringScreen(); // Lógica para entrar en una nueva pantalla, posiblemente con animación o retraso void handlePlayer1Entering(); // Controla la animación o posición de entrada del Jugador 1 en pantalla void handlePlayer2Entering(); // Controla la animación o posición de entrada del Jugador 2 en pantalla void handleCreditsMovement(); // Movimiento general en la pantalla de créditos (desplazamiento vertical u horizontal) void handleCreditsRightMovement(); // Lógica específica para mover los créditos hacia la derecha void handleCreditsLeftMovement(); // Lógica específica para mover los créditos hacia la izquierda void handleWaitingMovement(); // Controla la animación del jugador saludando void updateWalkingStateForCredits(); // Actualiza el estado de caminata de algún personaje u elemento animado en los créditos void setInputBasedOnPlayerId(); // Asocia las entradas de control en función del identificador del jugador (teclas, mando, etc.) void updateStepCounter(); // Incrementa o ajusta el contador de pasos para animaciones o mecánicas relacionadas con movimiento };