#pragma once #include // Para SDL_FRect #include // Para Uint32 #include // Para unique_ptr, shared_ptr #include // Para 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 Options, OptionsGame, options #include "utils.h" // Para Circle class Texture; enum class InputAction : int; enum class ScoreboardMode; // --- Estados del jugador --- enum class PlayerState { WALKING_LEFT, WALKING_RIGHT, WALKING_STOP, FIRING_UP, FIRING_LEFT, FIRING_RIGHT, FIRING_NONE, COOLING_UP, COOLING_LEFT, COOLING_RIGHT, PLAYING, // Está jugando CONTINUE, // Cuenta atrás para continuar WAITING, // No está jugando pero puede entrar a jugar ENTERING_NAME, // Introduciendo nombre SHOWING_NAME, // Mostrando el nombre introducido DYING, // El cadáver está volando por ahí DIED, // El cadáver ha desaparecido por el fondo GAME_OVER, // No está jugando y no puede entrar a jugar CELEBRATING, // Poniendo pose de victoria ENTERING_NAME_GAME_COMPLETED, // Poniendo nombre en el tramo final del juego LEAVING_SCREEN, // Moviéndose fuera de la pantalla ENTERING_SCREEN, // Entrando a la pantalla CREDITS, // Estado para los créditos del 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 --- int getRecordNamePos() const; // Obtiene la posición que se está editando del nombre del jugador para la tabla de mejores puntuaciones // Comprobación de playing_state bool hasDied() const { return playing_state_ == PlayerState::DIED; } bool isCelebrating() const { return playing_state_ == PlayerState::CELEBRATING; } bool isContinue() const { return playing_state_ == PlayerState::CONTINUE; } bool isDying() const { return playing_state_ == PlayerState::DYING; } bool isEnteringName() const { return playing_state_ == PlayerState::ENTERING_NAME; } bool isShowingName() const { return playing_state_ == PlayerState::SHOWING_NAME; } bool isEnteringNameGameCompleted() const { return playing_state_ == PlayerState::ENTERING_NAME_GAME_COMPLETED; } bool isLeavingScreen() const { return playing_state_ == PlayerState::LEAVING_SCREEN; } bool isGameOver() const { return playing_state_ == PlayerState::GAME_OVER; } bool isPlaying() const { return playing_state_ == PlayerState::PLAYING; } bool isWaiting() const { return playing_state_ == PlayerState::WAITING; } // Getters bool canFire() const { return cool_down_ <= 0; } bool hasExtraHit() const { return extra_hit_; } bool isCooling() const { return firing_state_ == PlayerState::COOLING_LEFT || firing_state_ == PlayerState::COOLING_UP || firing_state_ == PlayerState::COOLING_RIGHT; } bool IsEligibleForHighScore() const { return score_ > Options::settings.hi_score_table.back().score; } bool isInvulnerable() const { return invulnerable_; } bool isPowerUp() const { return power_up_; } Circle &getCollider() { return collider_; } float getScoreMultiplier() const { return score_multiplier_; } int getCoffees() const { return coffees_; } int getContinueCounter() const { return continue_counter_; } int getController() const { return controller_index_; } int getHeight() const { return HEIGHT_; } int getId() const { return id_; } int getInvulnerableCounter() const { return invulnerable_counter_; } int getPosX() const { return static_cast(pos_x_); } int getPosY() const { return pos_y_; } int getPowerUpCounter() const { return power_up_counter_; } std::string getRecordName() const { return enter_name_ ? enter_name_->getFinalName() : ""; } int getScore() const { return score_; } int getScoreBoardPanel() const { return scoreboard_panel_; } int getWidth() const { return WIDTH_; } PlayerState getPlayingState() const { return playing_state_; } const std::string &getName() const { return name_; } bool get1CC() const { return game_completed_ && credits_used_ == 1; } bool getEnterNamePositionOverflow() const { return enter_name_ ? enter_name_->getPositionOverflow() : false; } // Setters inline void setController(int index) { controller_index_ = index; } void setFireCooldown(int time) { cool_down_ = time; } 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 // --- 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 cool_down_ = 0; // Contador durante el cual no puede disparar 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_; // Para que el jugador sepa si está en el modo demostración int enter_name_counter_; // Contador para poner nombre Uint32 enter_name_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 decEnterNameCounter(); // Decrementa el contador de entrar nombre void updateScoreboard(); // Actualiza el panel del marcador void setScoreboardMode(ScoreboardMode mode); // Cambia el modo del marcador void playRandomBubbleSound(); // Hace sonar un sonido aleatorio bool isRenderable() const { return !isWaiting() && !isGameOver(); } };