#pragma once #include // Para Uint32, SDL_FRect #include // Para unique_ptr, shared_ptr #include // Para basic_string, string #include // Para vector #include "animated_sprite.h" // Para AnimatedSprite #include "enter_name.h" // Para EnterName #include "manage_hiscore_table.h" // Para HiScoreEntry #include "options.h" // Para SettingsOptions, settings #include "utils.h" // Para Circle class Texture; enum class InputAction : int; enum class ScoreboardMode; // --- Estados posibles del jugador --- enum class PlayerState { // 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á muriendo (animación de muerte) 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 }; // --- Clase Player --- class Player { public: // --- Constructor y destructor --- Player(int id, float x, int y, bool demo, SDL_FRect &play_area, std::vector> texture, const std::vector> &animations); ~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(InputAction input); // Procesa entrada general void setInputPlaying(InputAction input); // Procesa entrada en modo jugando void setInputEnteringName(InputAction input); // 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); // Añade puntos void incScoreMultiplier(); // Incrementa el multiplicador void decScoreMultiplier(); // Decrementa el multiplicador // --- Estados de juego --- void setPlayingState(PlayerState 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_ == PlayerState::LYING_ON_THE_FLOOR_FOREVER; } [[nodiscard]] auto isCelebrating() const -> bool { return playing_state_ == PlayerState::CELEBRATING; } [[nodiscard]] auto isContinue() const -> bool { return playing_state_ == PlayerState::CONTINUE; } [[nodiscard]] auto isDying() const -> bool { return playing_state_ == PlayerState::ROLLING; } [[nodiscard]] auto isEnteringName() const -> bool { return playing_state_ == PlayerState::ENTERING_NAME; } [[nodiscard]] auto isShowingName() const -> bool { return playing_state_ == PlayerState::SHOWING_NAME; } [[nodiscard]] auto isEnteringNameGameCompleted() const -> bool { return playing_state_ == PlayerState::ENTERING_NAME_GAME_COMPLETED; } [[nodiscard]] auto isLeavingScreen() const -> bool { return playing_state_ == PlayerState::LEAVING_SCREEN; } [[nodiscard]] auto isGameOver() const -> bool { return playing_state_ == PlayerState::GAME_OVER; } [[nodiscard]] auto isPlaying() const -> bool { return playing_state_ == PlayerState::PLAYING; } [[nodiscard]] auto isWaiting() const -> bool { return playing_state_ == PlayerState::WAITING; } [[nodiscard]] auto isTitleHidden() const -> bool { return playing_state_ == PlayerState::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_ == PlayerState::COOLING_LEFT || firing_state_ == PlayerState::COOLING_UP || firing_state_ == PlayerState::COOLING_RIGHT; } [[nodiscard]] auto isRecoiling() const -> bool { return firing_state_ == PlayerState::RECOILING_LEFT || firing_state_ == PlayerState::RECOILING_UP || firing_state_ == PlayerState::RECOILING_RIGHT; } [[nodiscard]] auto isEligibleForHighScore() const -> bool { return score_ > Options::settings.hi_score_table.back().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 -> int { 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 -> int { return scoreboard_panel_; } [[nodiscard]] static auto getWidth() -> int { return WIDTH; } [[nodiscard]] auto getPlayingState() const -> PlayerState { 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(PlayerState 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(int panel) { scoreboard_panel_ = panel; } void setScoreMultiplier(float value) { score_multiplier_ = value; } void setWalkingState(PlayerState state) { walking_state_ = state; } void addCredit() { ++credits_used_; } 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 int WIDTH = 30; // Anchura static constexpr int HEIGHT = 30; // Altura static constexpr float BASE_SPEED = 1.5F; // Velocidad base del jugador static constexpr int COOLING_DURATION = 50; static constexpr int COOLING_COMPLETE = 0; // --- 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 // --- Variables de estado --- int id_; // Número de identificación para el jugador. Player1 = 1, Player2 = 2 SDL_FRect play_area_; // Rectángulo con la zona de juego float pos_x_ = 0.0F; // Posición en el eje X int pos_y_ = 0; // Posición en el eje Y float default_pos_x_; // Posición inicial para el jugador int default_pos_y_; // Posición inicial para el jugador float vel_x_ = 0.0F; // Cantidad de píxeles a desplazarse en el eje X int vel_y_ = 0.0F; // 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; // Numero de frames que dura el estado de retroceso int cooling_state_counter_ = 0; // Contador para la animación del estado cooling int score_ = 0; // Puntos del jugador float score_multiplier_ = 1.0F; // Multiplicador de puntos PlayerState walking_state_ = PlayerState::WALKING_STOP; // Estado del jugador al moverse PlayerState firing_state_ = PlayerState::FIRING_NONE; // Estado del jugador al disparar PlayerState playing_state_ = PlayerState::WAITING; // Estado del jugador en el juego bool invulnerable_ = true; // Indica si el jugador es invulnerable int invulnerable_counter_ = INVULNERABLE_COUNTER; // Contador para la invulnerabilidad bool extra_hit_ = false; // Indica si el jugador tiene un toque extra int coffees_ = 0; // Indica cuántos cafés lleva acumulados bool power_up_ = false; // Indica si el jugador tiene activo el modo PowerUp int power_up_counter_ = POWERUP_COUNTER; // Temporizador para el modo PowerUp int power_up_desp_x_ = 0; // Desplazamiento del sprite de PowerUp respecto al sprite del jugador Circle collider_ = Circle(0, 0, 9); // Círculo de colisión del jugador int continue_counter_ = 10; // Contador para poder continuar Uint32 continue_ticks_ = 0; // Variable para poder cambiar el contador de continue en función del tiempo int scoreboard_panel_ = 0; // Panel del marcador asociado al jugador std::string name_; // Nombre del jugador int controller_index_ = 0; // Índice del array de mandos que utilizará para moverse bool demo_ = false; // Para que el jugador sepa si está en el modo demostración int name_entry_idle_counter_ = 0; // Contador para poner nombre int name_entry_total_counter_ = 0; // Segundos totales que lleva acumulados poniendo nombre 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 int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente bool game_completed_ = false; // Indica si ha completado el juego int credits_used_ = 1; // Indica el número de veces que ha continuado std::string last_enter_name_; // Último nombre introducido en la tabla de puntuaciones // --- 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(ScoreboardMode 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 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 };