diff --git a/source/bullet.cpp b/source/bullet.cpp index 1b72e97..3ff9524 100644 --- a/source/bullet.cpp +++ b/source/bullet.cpp @@ -7,7 +7,7 @@ #include "resource.h" // Para Resource // Constructor -Bullet::Bullet(float x, float y, BulletType bullet_type, bool powered, int owner) +Bullet::Bullet(float x, float y, BulletType bullet_type, bool powered, Player::Id owner) : sprite_(std::make_unique(Resource::get()->getTexture("bullet.png"), Resource::get()->getAnimation("bullet.ani"))), pos_x_(x), pos_y_(y), @@ -94,7 +94,7 @@ void Bullet::disable() { bullet_type_ = BulletType::NONE; } -auto Bullet::getOwner() const -> int { +auto Bullet::getOwner() const -> Player::Id { return owner_; } diff --git a/source/bullet.h b/source/bullet.h index 988ab84..2440eec 100644 --- a/source/bullet.h +++ b/source/bullet.h @@ -6,6 +6,7 @@ #include // Para string #include "animated_sprite.h" // Para AnimatedSprite +#include "player.h" // Para Player #include "utils.h" // Para Circle // Tipos de balas @@ -30,7 +31,7 @@ class Bullet { static constexpr float HEIGHT = 12.0F; // Constructor y Destructor - Bullet(float x, float y, BulletType bullet_type, bool powered, int owner); + Bullet(float x, float y, BulletType bullet_type, bool powered, Player::Id owner); ~Bullet() = default; // Métodos principales @@ -42,8 +43,8 @@ class Bullet { void disable(); // Desactiva la bala // Getters - [[nodiscard]] auto getOwner() const -> int; // Devuelve el identificador del dueño - auto getCollider() -> Circle &; // Devuelve el círculo de colisión + [[nodiscard]] auto getOwner() const -> Player::Id; // Devuelve el identificador del dueño + auto getCollider() -> Circle &; // Devuelve el círculo de colisión private: // Constantes @@ -60,7 +61,7 @@ class Bullet { float vel_x_; // Velocidad en el eje X BulletType bullet_type_; // Tipo de bala - int owner_; // Identificador del dueño + Player::Id owner_; // Identificador del dueño Circle collider_; // Círculo de colisión // Métodos internos diff --git a/source/define_buttons.cpp b/source/define_buttons.cpp index 81291f9..1100663 100644 --- a/source/define_buttons.cpp +++ b/source/define_buttons.cpp @@ -19,8 +19,9 @@ DefineButtons::DefineButtons() clearButtons(); - for (int i = 0; i < input_->getNumControllers(); ++i) { - // controller_names_.emplace_back(input_->getControllerName(i)); + auto gamepads = input_->getGamepads(); + for (auto gamepad : gamepads) { + controller_names_.emplace_back(input_->getControllerName(gamepad)); } } @@ -28,9 +29,9 @@ DefineButtons::DefineButtons() void DefineButtons::render() { static auto text = Resource::get()->getText("8bithud"); if (enabled_) { - // text->writeCentered(x_, y_ - 10, Lang::getText("[DEFINE_BUTTONS] PLAYER") + std::to_string(Options::controllers.at(index_controller_).player_id)); - // text->writeCentered(x_, y_, controller_names_.at(index_controller_)); - // text->writeCentered(x_, y_ + 10, buttons_.at(index_button_).label); + text->writeCentered(x_, y_ - 10, Lang::getText("[DEFINE_BUTTONS] PLAYER") + std::to_string(static_cast(gamepad_options_->player_id))); + text->writeCentered(x_, y_, gamepad_options_->instance->name); + text->writeCentered(x_, y_ + 10, buttons_.at(index_button_).label); } } @@ -76,15 +77,15 @@ void DefineButtons::checkEvents(const SDL_Event &event) { } // Habilita el objeto -auto DefineButtons::enable(int index) -> bool { - if (index < input_->getNumControllers()) { +auto DefineButtons::enable(std::shared_ptr gamepad_options) -> bool { + if (gamepad_options != nullptr) { + gamepad_options_ = gamepad_options; enabled_ = true; finished_ = false; index_button_ = 0; clearButtons(); return true; } - return false; } diff --git a/source/define_buttons.h b/source/define_buttons.h index 59feb6e..dc46a16 100644 --- a/source/define_buttons.h +++ b/source/define_buttons.h @@ -9,6 +9,7 @@ #include // Para vector #include "input.h" +#include "options.h" // Clase DefineButtons class DefineButtons { @@ -26,14 +27,14 @@ class DefineButtons { DefineButtons(); ~DefineButtons() = default; - void render(); // Dibuja el objeto en pantalla - void checkEvents(const SDL_Event &event); // Procesa los eventos - auto enable(int index_controller) -> bool; // Habilita la redefinición de botones - [[nodiscard]] auto isEnabled() const -> bool { return enabled_; }; // Comprueba si está habilitado + void render(); // Dibuja el objeto en pantalla + void checkEvents(const SDL_Event &event); // Procesa los eventos + auto enable(std::shared_ptr gamepad_options) -> bool; // Habilita la redefinición de botones + [[nodiscard]] auto isEnabled() const -> bool { return enabled_; }; // Comprueba si está habilitado private: // Objetos - Input *input_ = nullptr; // Gestión de entrada + Input *input_ = nullptr; // Gestión de entrada // Variables bool enabled_ = false; // Indica si está activo @@ -42,11 +43,12 @@ class DefineButtons { size_t index_button_ = 0; // Índice del botón en proceso std::vector controller_names_; // Nombres de los mandos bool finished_ = false; + std::shared_ptr gamepad_options_; // Métodos internos void incIndexButton(); // Incrementa el índice de botones void doControllerButtonDown(const SDL_GamepadButtonEvent &event); // Procesa pulsaciones - void bindButtons(std::shared_ptr gamepad); // Asigna botones al sistema de entrada + void bindButtons(std::shared_ptr gamepad); // Asigna botones al sistema de entrada void saveBindingsToOptions(); // Guarda configuraciones auto checkButtonNotInUse(SDL_GamepadButton button) -> bool; // Verifica uso de botones void clearButtons(); // Limpia asignaciones actuales diff --git a/source/director.cpp b/source/director.cpp index b18d502..6556b8d 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -102,7 +102,7 @@ void Director::init() { auto gamepads = Input::get()->getGamepads(); if (!gamepads.empty()) - Options::controllers.front().gamepad = gamepads.front(); + Options::gamepads.front()->instance = gamepads.front(); ServiceMenu::init(); // Inicializa el menú de servicio Notifier::init(std::string(), Resource::get()->getText("8bithud")); // Inicialización del sistema de notificaciones @@ -543,23 +543,19 @@ void Director::runTitle() { // Ejecuta la sección donde se juega al juego void Director::runGame() { - int player_id = 1; + Player::Id player_id = Player::Id::PLAYER1; switch (Section::options) { case Section::Options::GAME_PLAY_1P: - player_id = 1; + player_id = Player::Id::PLAYER1; break; - case Section::Options::GAME_PLAY_2P: - player_id = 2; + player_id = Player::Id::PLAYER2; break; - case Section::Options::GAME_PLAY_BOTH: - player_id = 0; + player_id = Player::Id::BOTH_PLAYERS; break; - default: - player_id = 1; break; } @@ -568,7 +564,7 @@ void Director::runGame() { #else constexpr int CURRENT_STAGE = 0; #endif - auto game = std::make_unique(player_id, CURRENT_STAGE, GAME_MODE_DEMO_OFF); + auto game = std::make_unique(player_id, CURRENT_STAGE, Game::DEMO_OFF); game->run(); } @@ -592,9 +588,9 @@ void Director::runHiScoreTable() { // Ejecuta el juego en modo demo void Director::runDemoGame() { - const auto PLAYER_ID = (rand() % 2) + 1; + const auto PLAYER_ID = static_cast((rand() % 2) + 1); constexpr auto CURRENT_STAGE = 0; - auto game = std::make_unique(PLAYER_ID, CURRENT_STAGE, GAME_MODE_DEMO_ON); + auto game = std::make_unique(PLAYER_ID, CURRENT_STAGE, Game::DEMO_ON); game->run(); } diff --git a/source/input.cpp b/source/input.cpp index 8c22823..1b7d36a 100644 --- a/source/input.cpp +++ b/source/input.cpp @@ -25,7 +25,7 @@ auto Input::get() -> Input * { return Input::instance; } // Constructor Input::Input(std::string game_controller_db_path, std::string gamepad_configs_file) - : game_controller_db_path_(std::move(game_controller_db_path)), + : gamepad_mappings_file_(std::move(game_controller_db_path)), gamepad_configs_file_(std::move(gamepad_configs_file)) { // Inicializa el subsistema SDL_INIT_GAMEPAD initSDLGamePad(); @@ -139,7 +139,7 @@ auto Input::gameControllerFound() const -> bool { return !gamepads_.empty(); } auto Input::getControllerName(std::shared_ptr gamepad) const -> std::string { return gamepad == nullptr ? std::string() : gamepad->name; } // Obten el número de mandos conectados -auto Input::getNumControllers() const -> int { return gamepads_.size(); } +auto Input::getNumGamepads() const -> int { return gamepads_.size(); } // Obtiene el indice del controlador a partir de un event.id auto Input::getJoyIndex(SDL_JoystickID id) const -> int { @@ -230,8 +230,8 @@ auto Input::checkAxisInput(Action input, std::shared_ptr gamepad, bool } void Input::addGamepadMappingsFromFile() { - if (SDL_AddGamepadMappingsFromFile(game_controller_db_path_.c_str()) < 0) { - std::cout << "Error, could not load " << game_controller_db_path_.c_str() << " file: " << SDL_GetError() << std::endl; + if (SDL_AddGamepadMappingsFromFile(gamepad_mappings_file_.c_str()) < 0) { + std::cout << "Error, could not load " << gamepad_mappings_file_.c_str() << " file: " << SDL_GetError() << std::endl; } } @@ -362,14 +362,13 @@ void Input::applyGamepadConfig(std::shared_ptr gamepad) { } // Buscar configuración por nombre del gamepad - auto configIt = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), - [&gamepad](const GamepadConfig& config) { - return config.name == gamepad->name; - }); + auto configIt = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), [&gamepad](const GamepadConfig &config) { + return config.name == gamepad->name; + }); if (configIt != gamepad_configs_.end()) { // Aplicar la configuración encontrada al gamepad - for (const auto& [action, button] : configIt->bindings) { + for (const auto &[action, button] : configIt->bindings) { if (gamepad->bindings.find(action) != gamepad->bindings.end()) { gamepad->bindings[action].button = button; } @@ -383,17 +382,16 @@ void Input::saveGamepadConfigFromGamepad(std::shared_ptr gamepad) { } // Buscar si ya existe una configuración con este nombre - auto configIt = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), - [&gamepad](const GamepadConfig& config) { - return config.name == gamepad->name; - }); + auto configIt = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), [&gamepad](const GamepadConfig &config) { + return config.name == gamepad->name; + }); // Crear nueva configuración desde el gamepad GamepadConfig newConfig(gamepad->name); newConfig.bindings.clear(); // Limpiar bindings por defecto - + // Copiar todos los bindings del gamepad - for (const auto& [action, buttonState] : gamepad->bindings) { + for (const auto &[action, buttonState] : gamepad->bindings) { newConfig.bindings[action] = buttonState.button; } @@ -410,33 +408,31 @@ void Input::saveGamepadConfigFromGamepad(std::shared_ptr gamepad) { } // Método para establecer el archivo de configuración (opcional) -void Input::setGamepadConfigsFile(const std::string& filename) { +void Input::setGamepadConfigsFile(const std::string &filename) { gamepad_configs_file_ = filename; loadGamepadConfigs(); // Recargar con el nuevo archivo } // Método para obtener configuración de un gamepad específico (opcional) -GamepadConfig* Input::getGamepadConfig(const std::string& gamepadName) { - auto configIt = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), - [&gamepadName](const GamepadConfig& config) { - return config.name == gamepadName; - }); - +GamepadConfig *Input::getGamepadConfig(const std::string &gamepadName) { + auto configIt = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), [&gamepadName](const GamepadConfig &config) { + return config.name == gamepadName; + }); + return (configIt != gamepad_configs_.end()) ? &(*configIt) : nullptr; } // Método para eliminar configuración de gamepad (opcional) -bool Input::removeGamepadConfig(const std::string& gamepadName) { - auto configIt = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), - [&gamepadName](const GamepadConfig& config) { - return config.name == gamepadName; - }); - +bool Input::removeGamepadConfig(const std::string &gamepadName) { + auto configIt = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), [&gamepadName](const GamepadConfig &config) { + return config.name == gamepadName; + }); + if (configIt != gamepad_configs_.end()) { gamepad_configs_.erase(configIt); saveGamepadConfigs(); return true; } - + return false; } \ No newline at end of file diff --git a/source/input.h b/source/input.h index 94bda29..fa59dab 100644 --- a/source/input.h +++ b/source/input.h @@ -49,54 +49,54 @@ class Input { }; struct Keyboard { - std::unordered_map bindings; + std::unordered_map bindings; Keyboard() : bindings{ // Teclado - Movimiento del jugador - {InputAction::UP, KeyState(SDL_SCANCODE_UP)}, - {InputAction::DOWN, KeyState(SDL_SCANCODE_DOWN)}, - {InputAction::LEFT, KeyState(SDL_SCANCODE_LEFT)}, - {InputAction::RIGHT, KeyState(SDL_SCANCODE_RIGHT)}, + {Action::UP, KeyState(SDL_SCANCODE_UP)}, + {Action::DOWN, KeyState(SDL_SCANCODE_DOWN)}, + {Action::LEFT, KeyState(SDL_SCANCODE_LEFT)}, + {Action::RIGHT, KeyState(SDL_SCANCODE_RIGHT)}, // Teclado - Disparo del jugador - {InputAction::FIRE_LEFT, KeyState(SDL_SCANCODE_Q)}, - {InputAction::FIRE_CENTER, KeyState(SDL_SCANCODE_W)}, - {InputAction::FIRE_RIGHT, KeyState(SDL_SCANCODE_E)}, + {Action::FIRE_LEFT, KeyState(SDL_SCANCODE_Q)}, + {Action::FIRE_CENTER, KeyState(SDL_SCANCODE_W)}, + {Action::FIRE_RIGHT, KeyState(SDL_SCANCODE_E)}, // Teclado - Interfaz - {InputAction::START, KeyState(SDL_SCANCODE_RETURN)}, + {Action::START, KeyState(SDL_SCANCODE_RETURN)}, // Teclado - Menu de servicio - {InputAction::SERVICE, KeyState(SDL_SCANCODE_0)}, - {InputAction::SM_SELECT, KeyState(SDL_SCANCODE_RETURN)}, - {InputAction::SM_BACK, KeyState(SDL_SCANCODE_BACKSPACE)}, + {Action::SERVICE, KeyState(SDL_SCANCODE_0)}, + {Action::SM_SELECT, KeyState(SDL_SCANCODE_RETURN)}, + {Action::SM_BACK, KeyState(SDL_SCANCODE_BACKSPACE)}, // Teclado - Control del programa - {InputAction::EXIT, KeyState(SDL_SCANCODE_ESCAPE)}, - {InputAction::PAUSE, KeyState(SDL_SCANCODE_P)}, - {InputAction::BACK, KeyState(SDL_SCANCODE_BACKSPACE)}, + {Action::EXIT, KeyState(SDL_SCANCODE_ESCAPE)}, + {Action::PAUSE, KeyState(SDL_SCANCODE_P)}, + {Action::BACK, KeyState(SDL_SCANCODE_BACKSPACE)}, - {InputAction::WINDOW_DEC_SIZE, KeyState(SDL_SCANCODE_F1)}, - {InputAction::WINDOW_INC_SIZE, KeyState(SDL_SCANCODE_F2)}, - {InputAction::WINDOW_FULLSCREEN, KeyState(SDL_SCANCODE_F3)}, - {InputAction::TOGGLE_VIDEO_SHADERS, KeyState(SDL_SCANCODE_F4)}, - {InputAction::TOGGLE_VIDEO_INTEGER_SCALE, KeyState(SDL_SCANCODE_F5)}, - {InputAction::TOGGLE_VIDEO_VSYNC, KeyState(SDL_SCANCODE_F6)}, + {Action::WINDOW_DEC_SIZE, KeyState(SDL_SCANCODE_F1)}, + {Action::WINDOW_INC_SIZE, KeyState(SDL_SCANCODE_F2)}, + {Action::WINDOW_FULLSCREEN, KeyState(SDL_SCANCODE_F3)}, + {Action::TOGGLE_VIDEO_SHADERS, KeyState(SDL_SCANCODE_F4)}, + {Action::TOGGLE_VIDEO_INTEGER_SCALE, KeyState(SDL_SCANCODE_F5)}, + {Action::TOGGLE_VIDEO_VSYNC, KeyState(SDL_SCANCODE_F6)}, - {InputAction::TOGGLE_AUDIO, KeyState(SDL_SCANCODE_F7)}, - {InputAction::TOGGLE_AUTO_FIRE, KeyState(SDL_SCANCODE_F8)}, - {InputAction::CHANGE_LANG, KeyState(SDL_SCANCODE_F9)}, + {Action::TOGGLE_AUDIO, KeyState(SDL_SCANCODE_F7)}, + {Action::TOGGLE_AUTO_FIRE, KeyState(SDL_SCANCODE_F8)}, + {Action::CHANGE_LANG, KeyState(SDL_SCANCODE_F9)}, - {InputAction::RESET, KeyState(SDL_SCANCODE_F10)}, - {InputAction::SHOW_INFO, KeyState(SDL_SCANCODE_F12)}} {} + {Action::RESET, KeyState(SDL_SCANCODE_F10)}, + {Action::SHOW_INFO, KeyState(SDL_SCANCODE_F12)}} {} }; struct Gamepad { SDL_Gamepad *pad; SDL_JoystickID instance_id; std::string name; - std::unordered_map bindings; + std::unordered_map bindings; Gamepad(SDL_Gamepad *gamepad) : pad(gamepad), @@ -104,19 +104,19 @@ class Input { name(std::string(SDL_GetGamepadName(gamepad))), bindings{ // Mando - Movimiento del jugador - {InputAction::UP, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_UP)}, - {InputAction::DOWN, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_DOWN)}, - {InputAction::LEFT, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_LEFT)}, - {InputAction::RIGHT, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_RIGHT)}, + {Action::UP, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_UP)}, + {Action::DOWN, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_DOWN)}, + {Action::LEFT, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_LEFT)}, + {Action::RIGHT, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_RIGHT)}, // Mando - Disparo del jugador - {InputAction::FIRE_LEFT, ButtonState(SDL_GAMEPAD_BUTTON_WEST)}, - {InputAction::FIRE_CENTER, ButtonState(SDL_GAMEPAD_BUTTON_NORTH)}, - {InputAction::FIRE_RIGHT, ButtonState(SDL_GAMEPAD_BUTTON_EAST)}, + {Action::FIRE_LEFT, ButtonState(SDL_GAMEPAD_BUTTON_WEST)}, + {Action::FIRE_CENTER, ButtonState(SDL_GAMEPAD_BUTTON_NORTH)}, + {Action::FIRE_RIGHT, ButtonState(SDL_GAMEPAD_BUTTON_EAST)}, // Mando - Interfaz - {InputAction::START, ButtonState(SDL_GAMEPAD_BUTTON_START)}, - {InputAction::SERVICE, ButtonState(SDL_GAMEPAD_BUTTON_BACK)}} {} + {Action::START, ButtonState(SDL_GAMEPAD_BUTTON_START)}, + {Action::SERVICE, ButtonState(SDL_GAMEPAD_BUTTON_BACK)}} {} ~Gamepad() { if (pad) { @@ -125,7 +125,7 @@ class Input { } // Reasigna un botón a una acción - void rebindAction(InputAction action, SDL_GamepadButton new_button) { + void rebindAction(Action action, SDL_GamepadButton new_button) { bindings[action] = new_button; } }; @@ -149,7 +149,7 @@ class Input { // --- Métodos de gestión de mandos --- [[nodiscard]] auto gameControllerFound() const -> bool; auto getControllerName(std::shared_ptr gamepad) const -> std::string; - [[nodiscard]] auto getNumControllers() const -> int; + [[nodiscard]] auto getNumGamepads() const -> int; [[nodiscard]] auto getJoyIndex(SDL_JoystickID id) const -> int; // --- Métodos de consulta y utilidades --- @@ -175,7 +175,7 @@ class Input { std::vector> gamepads_; Keyboard keyboard_; std::vector button_inputs_; - std::string game_controller_db_path_; + std::string gamepad_mappings_file_; std::string gamepad_configs_file_; GamepadConfigs gamepad_configs_; @@ -186,17 +186,17 @@ class Input { void remove_gamepad(SDL_JoystickID id); void addGamepadMappingsFromFile(); void discoverGamepads(); - + // --- Métodos para integración con GamepadConfigManager --- void loadGamepadConfigs(); void saveGamepadConfigs(); void applyGamepadConfig(std::shared_ptr gamepad); void saveGamepadConfigFromGamepad(std::shared_ptr gamepad); - + // Métodos auxiliares opcionales - void setGamepadConfigsFile(const std::string& filename); - GamepadConfig* getGamepadConfig(const std::string& gamepadName); - bool removeGamepadConfig(const std::string& gamepadName); + void setGamepadConfigsFile(const std::string &filename); + GamepadConfig *getGamepadConfig(const std::string &gamepadName); + bool removeGamepadConfig(const std::string &gamepadName); // --- Constructor y destructor --- explicit Input(std::string game_controller_db_path, std::string gamepad_configs_file); diff --git a/source/manage_hiscore_table.cpp b/source/manage_hiscore_table.cpp index 121c164..a8b08ba 100644 --- a/source/manage_hiscore_table.cpp +++ b/source/manage_hiscore_table.cpp @@ -51,7 +51,7 @@ auto ManageHiScoreTable::add(const HiScoreEntry &entry) -> int { // Si el nuevo elemento quedó fuera del top 10 if (position >= 10) { - position = -1; // No entró en el top 10 + position = NO_ENTRY; // No entró en el top 10 } } diff --git a/source/manage_hiscore_table.h b/source/manage_hiscore_table.h index b9d4352..29cd6ad 100644 --- a/source/manage_hiscore_table.h +++ b/source/manage_hiscore_table.h @@ -22,32 +22,29 @@ struct HiScoreEntry { : name(n.substr(0, 6)), score(s), one_credit_complete(occ) {} }; +using Table = std::vector; + // --- Clase ManageHiScoreTable --- class ManageHiScoreTable { public: - // Constructor - explicit ManageHiScoreTable(std::vector &table) - : table_(table) {} + // --- Constantes --- + static constexpr int NO_ENTRY = -1; - // Destructor + // Constructor y destructor + explicit ManageHiScoreTable(Table &table) + : table_(table) {} ~ManageHiScoreTable() = default; - // Resetea la tabla a los valores por defecto - void clear(); - - // Añade un elemento a la tabla (devuelve la posición en la que se inserta) - auto add(const HiScoreEntry &entry) -> int; - - // Carga la tabla con los datos de un fichero - auto loadFromFile(const std::string &file_path) -> bool; - - // Guarda la tabla en un fichero - auto saveToFile(const std::string &file_path) -> bool; + // --- Métodos públicos --- + void clear(); // Resetea la tabla a los valores por defecto + auto add(const HiScoreEntry &entry) -> int; // Añade un elemento a la tabla (devuelve la posición en la que se inserta) + auto loadFromFile(const std::string &file_path) -> bool; // Carga la tabla con los datos de un fichero + auto saveToFile(const std::string &file_path) -> bool; // Guarda la tabla en un fichero private: - // Referencia a la tabla con los records - std::vector &table_; + // --- Variables privadas --- + Table &table_; // Referencia a la tabla con los records - // Ordena la tabla internamente - void sort(); + // --- Métodos privados --- + void sort(); // Ordena la tabla }; \ No newline at end of file diff --git a/source/options.cpp b/source/options.cpp index 2a603f2..f35de86 100644 --- a/source/options.cpp +++ b/source/options.cpp @@ -19,13 +19,13 @@ namespace Options { // --- Variables globales --- -WindowOptions window; // Opciones de la ventana -SettingsOptions settings; // Opciones del juego -VideoOptions video; // Opciones de vídeo -AudioOptions audio; // Opciones de audio -std::vector controllers; // Opciones de mando para cada jugador -PendingChanges pending_changes; // Opciones que se aplican al cerrar -// std::vector gamepad_configs; // Lista con las configuraciones registradas para cada mando +Window window; // Opciones de la ventana +Settings settings; // Opciones del juego +Video video; // Opciones de vídeo +Audio audio; // Opciones de audio +std::vector> gamepads; // Opciones de mando para cada jugador +Keyboard keyboard; // Opciones para el teclado +PendingChanges pending_changes; // Opciones que se aplican al cerrar // Declaraciones auto set(const std::string& var, const std::string& value) -> bool; @@ -42,10 +42,10 @@ void init() { Difficulty::init(); // Opciones de control - controllers.clear(); - controllers.emplace_back(GamepadOptions(1)); - controllers.emplace_back(GamepadOptions(2)); - setKeyboardToPlayer(1); + gamepads.clear(); + gamepads.emplace_back(std::make_shared(Player::Id::PLAYER1)); + gamepads.emplace_back(std::make_shared(Player::Id::PLAYER2)); + setKeyboardToPlayer(Player::Id::PLAYER1); // Opciones de cambios pendientes pending_changes.new_language = settings.language; @@ -154,15 +154,15 @@ auto saveToFile() -> bool { // Opciones de mandos file << "\n\n## CONTROLLERS\n"; - int controller_index = 0; - for (const auto& controller : controllers) { - file << "\n"; - file << "controller." << controller_index << ".name=" << controller.name << "\n"; - file << "controller." << controller_index << ".player=" << controller.player_id << "\n"; - - // Incrementa el índice - ++controller_index; - } + // int controller_index = 0; + // for (const auto& controller : gamepads) { + // file << "\n"; + // file << "controller." << controller_index << ".name=" << controller->name << "\n"; + // file << "controller." << controller_index << ".player=" << controller->player_id << "\n"; + // + // // Incrementa el índice + // ++controller_index; + // } // Cierra el fichero file.close(); @@ -173,19 +173,19 @@ auto saveToFile() -> bool { // Función auxiliar para analizar la configuración del mando y reducir duplicación void parseAndSetController(const std::string& var, const std::string& value) { // Lógica básica de análisis (puede hacerse más robusta) - size_t first_dot = var.find('.'); - size_t second_dot = var.find('.', first_dot + 1); - - int controller_index = std::stoi(var.substr(first_dot + 1, second_dot - first_dot - 1)); - std::string setting_key = var.substr(second_dot + 1); - - auto& controller = controllers.at(controller_index); - - if (setting_key == "name") { - controller.name = value; - } else if (setting_key == "player") { - controller.player_id = std::clamp(std::stoi(value), 1, 2); - } + // size_t first_dot = var.find('.'); + // size_t second_dot = var.find('.', first_dot + 1); + // + // int controller_index = std::stoi(var.substr(first_dot + 1, second_dot - first_dot - 1)); + // std::string setting_key = var.substr(second_dot + 1); + // + // auto& controller = gamepads.at(controller_index); + // + // if (setting_key == "name") { + // controller.name = value; + // } else if (setting_key == "player") { + // controller.player_id = std::clamp(std::stoi(value), 1, 2); + // } } auto set(const std::string& var, const std::string& value) -> bool { @@ -254,35 +254,23 @@ auto set(const std::string& var, const std::string& value) -> bool { } // Asigna el teclado al jugador -void setKeyboardToPlayer(int player_id) { - for (auto& controller : controllers) { - if (controller.player_id == player_id) { - // controller.type = Input::Device::ANY; - } else { - // controller.type = Input::Device::CONTROLLER; - } - } +void setKeyboardToPlayer(Player::Id player_id) { + keyboard.player_id = player_id; } // Intercambia el teclado de jugador void swapKeyboard() { - // std::swap(controllers.at(0).type, controllers.at(1).type); + keyboard.player_id = keyboard.player_id == Player::Id::PLAYER1 ? Player::Id::PLAYER2 : Player::Id::PLAYER1; } // Intercambia los jugadores asignados a los dos primeros mandos void swapControllers() { - std::swap(controllers.at(0).player_id, controllers.at(1).player_id); - // std::swap(controllers.at(0).type, controllers.at(1).type); + std::swap(gamepads.at(0)->player_id, gamepads.at(1)->player_id); } // Averigua quien está usando el teclado -auto getPlayerWhoUsesKeyboard() -> int { - // for (const auto& controller : controllers) { - // if (controller.type == Input::Device::ANY) { - // return controller.player_id; - // } - //} - return 0; +auto getPlayerWhoUsesKeyboard() -> Player::Id { + return keyboard.player_id; } // Aplica los cambios pendientes copiando los valores a sus variables diff --git a/source/options.h b/source/options.h index b696912..a38f05b 100644 --- a/source/options.h +++ b/source/options.h @@ -8,28 +8,26 @@ #include #include // Para vector -#include "difficulty.h" // Para Code -// #include "gamepad_config_manager.h" +#include "difficulty.h" // Para Code #include "input.h" // Para InputAction, InputDevice #include "lang.h" // Para Code #include "manage_hiscore_table.h" // Para HiScoreEntry - -static constexpr int INVALID_INDEX = -1; +#include "player.h" // Para Player namespace Options { // --- Opciones de ventana --- -struct WindowOptions { +struct Window { std::string caption; // Texto que aparece en la barra de título de la ventana int zoom{2}; // Valor por el que se multiplica el tamaño de la ventana int max_zoom{2}; // Tamaño máximo para que la ventana no sea mayor que la pantalla // Constructor por defecto con valores iniciales - WindowOptions() + Window() : caption("Coffee Crisis Arcade Edition") {} }; // --- Opciones de vídeo --- -struct VideoOptions { +struct Video { SDL_ScaleMode scale_mode{SDL_ScaleMode::SDL_SCALEMODE_NEAREST}; // Filtro usado para el escalado de la imagen bool fullscreen{false}; // Indica si se usa pantalla completa bool vsync{true}; // Indica si se usa vsync @@ -38,69 +36,73 @@ struct VideoOptions { std::string info; // Información sobre el modo de vídeo // Constructor por defecto con valores iniciales - VideoOptions() = default; + Video() = default; }; // --- Opciones de música --- -struct MusicOptions { +struct Music { bool enabled{true}; // Indica si la música suena o no int volume{100}; // Volumen de la música // Constructor por defecto - MusicOptions() = default; + Music() = default; }; // --- Opciones de sonido --- -struct SoundOptions { +struct Sound { bool enabled{true}; // Indica si los sonidos suenan o no int volume{100}; // Volumen de los sonidos // Constructor por defecto - SoundOptions() = default; + Sound() = default; }; // --- Opciones de audio --- -struct AudioOptions { - MusicOptions music; // Opciones para la música - SoundOptions sound; // Opciones para los efectos de sonido +struct Audio { + Music music; // Opciones para la música + Sound sound; // Opciones para los efectos de sonido bool enabled{true}; // Indica si el audio está activo o no int volume{100}; // Volumen general del audio // Constructor por defecto - AudioOptions() = default; + Audio() = default; }; // --- Opciones de configuración --- -struct SettingsOptions { +struct Settings { Difficulty::Code difficulty{Difficulty::Code::NORMAL}; // Dificultad del juego Lang::Code language{Lang::Code::VALENCIAN}; // Idioma usado en el juego bool autofire{true}; // Indicador de autofire bool shutdown_enabled{false}; // Especifica si se puede apagar el sistema - std::vector hi_score_table; // Tabla de mejores puntuaciones - std::vector last_hi_score_entry; // Últimas posiciones de entrada en la tabla + Table hi_score_table; // Tabla de mejores puntuaciones + std::vector glowing_entries; // Últimas posiciones de entrada en la tabla std::string config_file; // Ruta al fichero donde guardar la configuración y las opciones del juego std::string controllers_file; // Ruta al fichero con las configuraciones de los mandos // Constructor por defecto con valores iniciales - SettingsOptions() - : last_hi_score_entry({INVALID_INDEX, INVALID_INDEX}) {} + Settings() + : glowing_entries({ManageHiScoreTable::NO_ENTRY, ManageHiScoreTable::NO_ENTRY}) {} // Reinicia las últimas entradas de puntuación void clearLastHiScoreEntries() { - last_hi_score_entry.at(0) = INVALID_INDEX; - last_hi_score_entry.at(1) = INVALID_INDEX; + glowing_entries.at(0) = ManageHiScoreTable::NO_ENTRY; + glowing_entries.at(1) = ManageHiScoreTable::NO_ENTRY; } }; -struct GamepadOptions { - std::shared_ptr gamepad = nullptr; // Referencia al mando - std::string name; // Nombre del mando - int player_id; // Jugador asociado al mando +struct Gamepad { + std::shared_ptr instance = nullptr; // Referencia al mando + std::string name; // Nombre del mando + Player::Id player_id; // Jugador asociado al mando - GamepadOptions(int custom_player_id = INVALID_INDEX) + Gamepad(Player::Id custom_player_id = Player::Id::NO_PLAYER) : player_id(custom_player_id) {} }; +struct Keyboard { + Player::Id player_id = Player::Id::PLAYER1; // Jugador asociado al teclado +}; + // --- Opciones pendientes de aplicar --- struct PendingChanges { Lang::Code new_language{Lang::Code::VALENCIAN}; // Idioma en espera de aplicar @@ -112,12 +114,13 @@ struct PendingChanges { }; // --- Variables globales --- -extern WindowOptions window; // Opciones de la ventana -extern SettingsOptions settings; // Opciones del juego -extern VideoOptions video; // Opciones de vídeo -extern AudioOptions audio; // Opciones de audio -extern std::vector controllers; // Opciones de mando para cada jugador -extern PendingChanges pending_changes; // Opciones que se aplican al cerrar +extern Window window; // Opciones de la ventana +extern Settings settings; // Opciones del juego +extern Video video; // Opciones de vídeo +extern Audio audio; // Opciones de audio +extern std::vector> gamepads; // Opciones de mando para cada jugador +extern Keyboard keyboard; // Opciones para el teclado +extern PendingChanges pending_changes; // Opciones que se aplican al cerrar // --- Funciones de configuración --- void init(); // Inicializa las opciones del programa @@ -125,10 +128,10 @@ void setConfigFile(const std::string &file_path); // Establece el fichero void setControllersFile(const std::string &file_path); // Establece el fichero de configuración de mandos auto loadFromFile() -> bool; // Carga el fichero de configuración auto saveToFile() -> bool; // Guarda el fichero de configuración -void setKeyboardToPlayer(int player_id); // Asigna el teclado al jugador +void setKeyboardToPlayer(Player::Id player_id); // Asigna el teclado al jugador void swapKeyboard(); // Intercambia el teclado de jugador void swapControllers(); // Intercambia los jugadores asignados a los dos primeros mandos -auto getPlayerWhoUsesKeyboard() -> int; // Averigua quién está usando el teclado +auto getPlayerWhoUsesKeyboard() -> Player::Id; // Averigua quién está usando el teclado void applyPendingChanges(); // Aplica los cambios pendientes copiando los valores a sus variables void checkPendingChanges(); // Verifica si hay cambios pendientes diff --git a/source/player.cpp b/source/player.cpp index 503041c..a99712b 100644 --- a/source/player.cpp +++ b/source/player.cpp @@ -16,20 +16,22 @@ #include "texture.h" // Para Texture // Constructor -Player::Player(int id, float x, int y, bool demo, SDL_FRect &play_area, std::vector> texture, const std::vector> &animations) - : player_sprite_(std::make_unique(texture.at(0), animations.at(0))), - power_sprite_(std::make_unique(texture.at(1), animations.at(1))), +Player::Player(const Config& config) + : player_sprite_(std::make_unique(config.texture.at(0), config.animations.at(0))), + power_sprite_(std::make_unique(config.texture.at(1), config.animations.at(1))), enter_name_(std::make_unique()), - id_(id), - play_area_(play_area), - default_pos_x_(x), - default_pos_y_(y), - demo_(demo) { + id_(config.id), + play_area_(*config.play_area), + default_pos_x_(config.x), + default_pos_y_(config.y), + hi_score_table_(*config.hi_score_table), + glowing_entry_(*config.glowing_entry), + demo_(config.demo) { // Configura objetos player_sprite_->getTexture()->setPalette(coffees_); power_sprite_->getTexture()->setAlpha(224); power_up_x_offset_ = (power_sprite_->getWidth() - player_sprite_->getWidth()) / 2; - power_sprite_->setPosY(y - (power_sprite_->getHeight() - player_sprite_->getHeight())); + power_sprite_->setPosY(default_pos_y_ - (power_sprite_->getHeight() - player_sprite_->getHeight())); // Inicializa variables pos_x_ = default_pos_x_; @@ -219,8 +221,8 @@ void Player::handleRollingGroundCollision() { } void Player::handleRollingStop() { - const auto NEXT_PLAYER_STATUS = isEligibleForHighScore() ? State::ENTERING_NAME : State::CONTINUE; - const auto NEXT_STATE = demo_ ? State::LYING_ON_THE_FLOOR_FOREVER : NEXT_PLAYER_STATUS; + const auto NEXT_PLAYER_STATE = qualifiesForHighScore() ? State::ENTERING_NAME : State::CONTINUE; + const auto NEXT_STATE = demo_ ? State::LYING_ON_THE_FLOOR_FOREVER : NEXT_PLAYER_STATE; setPlayingState(NEXT_STATE); pos_x_ = player_sprite_->getPosX(); @@ -278,10 +280,15 @@ void Player::handleLeavingScreen() { void Player::handleEnteringScreen() { updateStepCounter(); - if (id_ == 1) { - handlePlayer1Entering(); - } else if (id_ == 2) { - handlePlayer2Entering(); + switch (id_) { + case Id::PLAYER1: + handlePlayer1Entering(); + break; + case Id::PLAYER2: + handlePlayer2Entering(); + break; + default: + break; } shiftSprite(); @@ -350,10 +357,10 @@ void Player::updateWalkingStateForCredits() { void Player::setInputBasedOnPlayerId() { switch (id_) { - case 1: + case Id::PLAYER1: setInputPlaying(Input::Action::LEFT); break; - case 2: + case Id::PLAYER2: setInputPlaying(Input::Action::RIGHT); break; default: @@ -552,9 +559,10 @@ void Player::update() { } // Incrementa la puntuación del jugador -void Player::addScore(int score) { +void Player::addScore(int score, int last_hi_score_entry) { if (isPlaying()) { score_ += score; + qualifies_for_high_score_ = score_ > last_hi_score_entry; } } @@ -611,10 +619,10 @@ void Player::setPlayingState(State state) { } case State::WAITING: { switch (id_) { - case 1: + case Id::PLAYER1: pos_x_ = param.game.game_area.rect.x; break; - case 2: + case Id::PLAYER2: pos_x_ = param.game.game_area.rect.w - WIDTH; break; default: @@ -698,11 +706,11 @@ void Player::setPlayingState(State state) { step_counter_ = 0; setScoreboardMode(Scoreboard::Mode::SCORE); switch (id_) { - case 1: + case Id::PLAYER1: pos_x_ = param.game.game_area.rect.x - WIDTH; break; - case 2: + case Id::PLAYER2: pos_x_ = param.game.game_area.rect.x + param.game.game_area.rect.w; break; @@ -898,7 +906,7 @@ auto Player::isRenderable() const -> bool { // Añade una puntuación a la tabla de records void Player::addScoreToScoreBoard() const { const auto ENTRY = HiScoreEntry(trim(getLastEnterName()), getScore(), get1CC()); - auto manager = std::make_unique(Options::settings.hi_score_table); - Options::settings.last_hi_score_entry.at(getId() - 1) = manager->add(ENTRY); + auto manager = std::make_unique(hi_score_table_); + glowing_entry_ = manager->add(ENTRY); manager->saveToFile(Asset::get()->get("score.bin")); } \ No newline at end of file diff --git a/source/player.h b/source/player.h index 5186a20..4aaede8 100644 --- a/source/player.h +++ b/source/player.h @@ -10,7 +10,6 @@ #include "enter_name.h" // Para EnterName #include "input.h" #include "manage_hiscore_table.h" // Para HiScoreEntry -#include "options.h" // Para SettingsOptions, settings #include "scoreboard.h" // Para Scoreboard #include "utils.h" // Para Circle @@ -25,6 +24,14 @@ class Player { 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 @@ -68,8 +75,20 @@ class Player { 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(int id, float x, int y, bool demo, SDL_FRect &play_area, std::vector> texture, const std::vector> &animations); + Player(const Config& config); ~Player() = default; // --- Inicialización y ciclo de vida --- @@ -93,9 +112,9 @@ class Player { 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 + 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 @@ -128,7 +147,7 @@ class Player { [[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 isEligibleForHighScore() const -> bool { return score_ > Options::settings.hi_score_table.back().score; } + [[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_; } @@ -137,7 +156,7 @@ class Player { [[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 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_; } @@ -165,11 +184,13 @@ class Player { void setWalkingState(State state) { walking_state_ = state; } void addCredit() { ++credits_used_; } - // Setter y getter para gamepad_ void setGamepad(std::shared_ptr gamepad) { gamepad_ = gamepad; } [[nodiscard]] std::shared_ptr getGamepad() const { return gamepad_; } void setUsesKeyboard(bool value) { uses_keyboard_ = value; } [[nodiscard]] bool getUsesKeyboard() const { return uses_keyboard_; } + void setHiScoreTable(const Table &table) { hi_score_table_ = table; } + const Table &getHiScoreTable() const { return hi_score_table_; } + void setGlowingEntry(const int &entry) { glowing_entry_ = entry; } private: // --- Constantes --- @@ -186,7 +207,7 @@ class Player { 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 + Id id_; // Identificador para el jugador 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 @@ -200,6 +221,9 @@ class Player { 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 + bool qualifies_for_high_score_ = false; // Indica si tiene una puntuación que le permite entrar en la tabla de records + Table &hi_score_table_; // Tabla de maximas puntuaciones + int &glowing_entry_; // Entrada de la tabla de puntuaciones para hacerla brillar 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 diff --git a/source/sections/credits.cpp b/source/sections/credits.cpp index 08e52d8..8256980 100644 --- a/source/sections/credits.cpp +++ b/source/sections/credits.cpp @@ -353,11 +353,32 @@ void Credits::initPlayers() { const int Y = play_area_.y + play_area_.h - PLAYER_WIDTH; constexpr bool DEMO = false; constexpr int AWAY_DISTANCE = 700; - players_.emplace_back(std::make_unique(1, play_area_.x - AWAY_DISTANCE - PLAYER_WIDTH, Y, DEMO, play_area_, player_textures.at(0), player_animations)); + + Player::Config config_player1; + config_player1.id = Player::Id::PLAYER1; + config_player1.x = play_area_.x - AWAY_DISTANCE - PLAYER_WIDTH; + config_player1.y = Y; + config_player1.demo = DEMO; + config_player1.play_area = &play_area_; + config_player1.texture = player_textures.at(0); + config_player1.animations = player_animations; + config_player1.hi_score_table = &Options::settings.hi_score_table; + config_player1.glowing_entry = &Options::settings.glowing_entries.at(static_cast(Player::Id::PLAYER1) - 1); + players_.emplace_back(std::make_unique(config_player1)); players_.back()->setWalkingState(Player::State::WALKING_RIGHT); players_.back()->setPlayingState(Player::State::CREDITS); - players_.emplace_back(std::make_unique(2, play_area_.x + play_area_.w + AWAY_DISTANCE, Y, DEMO, play_area_, player_textures.at(1), player_animations)); + Player::Config config_player2; + config_player2.id = Player::Id::PLAYER2; + config_player2.x = play_area_.x + play_area_.w + AWAY_DISTANCE; + config_player2.y = Y; + config_player2.demo = DEMO; + config_player2.play_area = &play_area_; + config_player2.texture = player_textures.at(1); + config_player2.animations = player_animations; + config_player2.hi_score_table = &Options::settings.hi_score_table; + config_player2.glowing_entry = &Options::settings.glowing_entries.at(static_cast(Player::Id::PLAYER2) - 1); + players_.emplace_back(std::make_unique(config_player2)); players_.back()->setWalkingState(Player::State::WALKING_LEFT); players_.back()->setPlayingState(Player::State::CREDITS); } diff --git a/source/sections/game.cpp b/source/sections/game.cpp index c6feb33..30cebc3 100644 --- a/source/sections/game.cpp +++ b/source/sections/game.cpp @@ -42,7 +42,7 @@ #include "ui/service_menu.h" // Para ServiceMenu // Constructor -Game::Game(int player_id, int current_stage, bool demo) +Game::Game(Player::Id player_id, int current_stage, bool demo) : renderer_(Screen::get()->getRenderer()), screen_(Screen::get()), input_(Input::get()), @@ -365,7 +365,7 @@ void Game::updateGameStateCompleted() { for (auto &player : players_) { if (player->isPlaying()) { - player->addScore(1000000); + player->addScore(1000000, Options::settings.hi_score_table.back().score); player->setPlayingState(Player::State::CELEBRATING); } else { player->setPlayingState(Player::State::GAME_OVER); @@ -379,7 +379,7 @@ void Game::updateGameStateCompleted() { if (game_completed_counter_ == END_CELEBRATIONS) { for (auto &player : players_) { if (player->isCelebrating()) { - player->setPlayingState(player->isEligibleForHighScore() ? Player::State::ENTERING_NAME_GAME_COMPLETED : Player::State::LEAVING_SCREEN); + player->setPlayingState(player->qualifiesForHighScore() ? Player::State::ENTERING_NAME_GAME_COMPLETED : Player::State::LEAVING_SCREEN); } } } @@ -435,28 +435,28 @@ void Game::checkPlayerItemCollision(std::shared_ptr &player) { if (checkCollision(player->getCollider(), item->getCollider())) { switch (item->getType()) { case ItemType::DISK: { - player->addScore(1000); + player->addScore(1000, Options::settings.hi_score_table.back().score); const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(0)->getWidth()) / 2; createItemText(X, game_text_textures_.at(0)); playSound("item_pickup.wav"); break; } case ItemType::GAVINA: { - player->addScore(2500); + player->addScore(2500, Options::settings.hi_score_table.back().score); const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(1)->getWidth()) / 2; createItemText(X, game_text_textures_.at(1)); playSound("item_pickup.wav"); break; } case ItemType::PACMAR: { - player->addScore(5000); + player->addScore(5000, Options::settings.hi_score_table.back().score); const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(2)->getWidth()) / 2; createItemText(X, game_text_textures_.at(2)); playSound("item_pickup.wav"); break; } case ItemType::DEBIAN: { - player->addScore(100000); + player->addScore(100000, Options::settings.hi_score_table.back().score); const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(6)->getWidth()) / 2; createItemText(X, game_text_textures_.at(6)); playSound("debian_pickup.wav"); @@ -471,7 +471,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr &player) { } case ItemType::COFFEE: { if (player->getCoffees() == 2) { - player->addScore(5000); + player->addScore(5000, Options::settings.hi_score_table.back().score); const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(2)->getWidth()) / 2; createItemText(X, game_text_textures_.at(2)); } else { @@ -594,11 +594,11 @@ void Game::handleItemDrop(std::shared_ptr balloon, std::shared_ptr balloon, std::shared_ptr player) { - const auto SCORE = balloon_manager_->popBalloon(balloon); evaluateAndSetMenace(); if (player->isPlaying()) { - player->addScore(SCORE * player->getScoreMultiplier() * difficulty_score_multiplier_); + auto const SCORE = balloon_manager_->popBalloon(balloon) * player->getScoreMultiplier() * difficulty_score_multiplier_; + player->addScore(SCORE, Options::settings.hi_score_table.back().score); player->incScoreMultiplier(); } updateHiScore(); @@ -621,7 +621,7 @@ void Game::renderBullets() { } // Crea un objeto bala -void Game::createBullet(int x, int y, BulletType kind, bool powered_up, int owner) { +void Game::createBullet(int x, int y, BulletType kind, bool powered_up, Player::Id owner) { bullets_.emplace_back(std::make_shared(x, y, kind, powered_up, owner)); } @@ -1174,7 +1174,7 @@ void Game::pause(bool value) { void Game::addScoreToScoreBoard(const std::shared_ptr &player) { const auto ENTRY = HiScoreEntry(trim(player->getLastEnterName()), player->getScore(), player->get1CC()); auto manager = std::make_unique(Options::settings.hi_score_table); - Options::settings.last_hi_score_entry.at(player->getId() - 1) = manager->add(ENTRY); + Options::settings.glowing_entries.at(static_cast(player->getId()) - 1) = manager->add(ENTRY); manager->saveToFile(Asset::get()->get("score.bin")); hi_score_.name = Options::settings.hi_score_table.front().name; } @@ -1206,7 +1206,7 @@ void Game::checkPlayersStatusPlaying() { } // Obtiene un jugador a partir de su "id" -auto Game::getPlayer(int id) -> std::shared_ptr { +auto Game::getPlayer(Player::Id id) -> std::shared_ptr { auto it = std::find_if(players_.begin(), players_.end(), [id](const auto &player) { return player->getId() == id; }); if (it != players_.end()) { @@ -1216,11 +1216,11 @@ auto Game::getPlayer(int id) -> std::shared_ptr { } // Obtiene un controlador a partir del "id" del jugador -auto Game::getController(int player_id) -> int { - auto it = std::find_if(Options::controllers.begin(), Options::controllers.end(), [player_id](const auto &controller) { return controller.player_id == player_id; }); +auto Game::getController(Player::Id player_id) -> int { + auto it = std::find_if(Options::gamepads.begin(), Options::gamepads.end(), [player_id](const auto &controller) { return controller->player_id == player_id; }); - if (it != Options::controllers.end()) { - return std::distance(Options::controllers.begin(), it); + if (it != Options::gamepads.end()) { + return std::distance(Options::gamepads.begin(), it); } return -1; @@ -1286,7 +1286,7 @@ void Game::demoHandleInput() { // Procesa las entradas para un jugador específico durante el modo demo. void Game::demoHandlePlayerInput(const std::shared_ptr &player, int index) { - const auto &demo_data = demo_.data[index][demo_.counter]; + const auto &demo_data = demo_.data.at(index).at(demo_.counter); if (demo_data.left == 1) { player->setInput(Input::Action::LEFT); @@ -1469,7 +1469,7 @@ void Game::handleNameInput(const std::shared_ptr &player) { } // Inicializa las variables para el modo DEMO -void Game::initDemo(int player_id) { +void Game::initDemo(Player::Id player_id) { if (demo_.enabled) { // Cambia el estado del juego setState(State::PLAYING); @@ -1497,7 +1497,7 @@ void Game::initDemo(int player_id) { // Activa o no al otro jugador if (rand() % 3 != 0) { - const auto OTHER_PLAYER_ID = player_id == 1 ? 2 : 1; + const auto OTHER_PLAYER_ID = player_id == Player::Id::PLAYER1 ? Player::Id::PLAYER2 : Player::Id::PLAYER1; auto other_player = getPlayer(OTHER_PLAYER_ID); other_player->setPlayingState(Player::State::PLAYING); } @@ -1581,30 +1581,54 @@ void Game::initDifficultyVars() { } // Inicializa los jugadores -void Game::initPlayers(int player_id) { +void Game::initPlayers(Player::Id player_id) { const int Y = param.game.play_area.rect.h - Player::HEIGHT + 1; // Se hunde un pixel para esconder el outline de los pies // Crea al jugador uno y lo pone en modo espera - players_.emplace_back(std::make_unique(1, param.game.play_area.first_quarter_x - (Player::WIDTH / 2), Y, demo_.enabled, param.game.play_area.rect, player_textures_.at(0), player_animations_)); - players_.back()->setScoreBoardPanel(Scoreboard::Id::LEFT); - players_.back()->setName(Lang::getText("[SCOREBOARD] 1")); - //players_.back()->setController(getController(players_.back()->getId())); - players_.back()->setGamepad(Options::controllers.front().gamepad); - players_.back()->setUsesKeyboard(true); - players_.back()->setPlayingState(Player::State::WAITING); + Player::Config config_player1; + config_player1.id = Player::Id::PLAYER1; + config_player1.x = param.game.play_area.first_quarter_x - (Player::WIDTH / 2); + config_player1.y = Y; + config_player1.demo = demo_.enabled; + config_player1.play_area = ¶m.game.play_area.rect; + config_player1.texture = player_textures_.at(0); + config_player1.animations = player_animations_; + config_player1.hi_score_table = &Options::settings.hi_score_table; + config_player1.glowing_entry = &Options::settings.glowing_entries.at(static_cast(Player::Id::PLAYER1) - 1); + + auto player1 = std::make_unique(config_player1); + player1->setScoreBoardPanel(Scoreboard::Id::LEFT); + player1->setName(Lang::getText("[SCOREBOARD] 1")); + player1->setGamepad(Options::gamepads.front()->instance); + player1->setUsesKeyboard(Player::Id::PLAYER1 == Options::keyboard.player_id); + player1->setPlayingState(Player::State::WAITING); + players_.push_back(std::move(player1)); // Crea al jugador dos y lo pone en modo espera - players_.emplace_back(std::make_unique(2, param.game.play_area.third_quarter_x - (Player::WIDTH / 2), Y, demo_.enabled, param.game.play_area.rect, player_textures_.at(1), player_animations_)); - players_.back()->setScoreBoardPanel(Scoreboard::Id::RIGHT); - players_.back()->setName(Lang::getText("[SCOREBOARD] 2")); - //players_.back()->setController(getController(players_.back()->getId())); - players_.back()->setPlayingState(Player::State::WAITING); + Player::Config config_player2; + config_player2.id = Player::Id::PLAYER2; + config_player2.x = param.game.play_area.third_quarter_x - (Player::WIDTH / 2); + config_player2.y = Y; + config_player2.demo = demo_.enabled; + config_player2.play_area = ¶m.game.play_area.rect; + config_player2.texture = player_textures_.at(1); + config_player2.animations = player_animations_; + config_player2.hi_score_table = &Options::settings.hi_score_table; + config_player2.glowing_entry = &Options::settings.glowing_entries.at(static_cast(Player::Id::PLAYER2) - 1); + + auto player2 = std::make_unique(config_player2); + player2->setScoreBoardPanel(Scoreboard::Id::RIGHT); + player2->setName(Lang::getText("[SCOREBOARD] 2")); + player2->setGamepad(Options::gamepads.back()->instance); + player2->setUsesKeyboard(Player::Id::PLAYER2 == Options::keyboard.player_id); + player2->setPlayingState(Player::State::WAITING); + players_.push_back(std::move(player2)); // Activa el jugador que coincide con el "player_id" o ambos si es "0" - if (player_id == 0) { + if (player_id == Player::Id::BOTH_PLAYERS) { // Activa ambos jugadores - getPlayer(1)->setPlayingState(demo_.enabled ? Player::State::PLAYING : Player::State::ENTERING_SCREEN); - getPlayer(2)->setPlayingState(demo_.enabled ? Player::State::PLAYING : Player::State::ENTERING_SCREEN); + getPlayer(Player::Id::PLAYER1)->setPlayingState(demo_.enabled ? Player::State::PLAYING : Player::State::ENTERING_SCREEN); + getPlayer(Player::Id::PLAYER2)->setPlayingState(demo_.enabled ? Player::State::PLAYING : Player::State::ENTERING_SCREEN); } else { // Activa el jugador elegido auto player = getPlayer(player_id); diff --git a/source/sections/game.h b/source/sections/game.h index cccdc01..24da296 100644 --- a/source/sections/game.h +++ b/source/sections/game.h @@ -30,18 +30,15 @@ namespace Difficulty { enum class Code; } // namespace Difficulty -// Modo demo -constexpr bool GAME_MODE_DEMO_OFF = false; -constexpr bool GAME_MODE_DEMO_ON = true; - -// Cantidad de elementos a escribir en los ficheros de datos -constexpr int TOTAL_SCORE_DATA = 3; - // Clase Game class Game { public: + // --- Constantes --- + static constexpr bool DEMO_OFF = false; + static constexpr bool DEMO_ON = true; + // --- Constructor y destructor --- - Game(int player_id, int current_stage, bool demo); + Game(Player::Id player_id, int current_stage, bool demo); ~Game(); // --- Bucle principal --- @@ -174,12 +171,12 @@ class Game { void updateGameStateGameOver(); // Gestiona el estado de fin de partida // --- Gestión de jugadores --- - void initPlayers(int player_id); // Inicializa los datos de los jugadores - void updatePlayers(); // Actualiza las variables y estados de los jugadores - void renderPlayers(); // Renderiza todos los jugadores en pantalla - void sortPlayersByZOrder(); // Reorganiza el orden de dibujado de jugadores - auto getPlayer(int id) -> std::shared_ptr; // Obtiene un jugador por su identificador - static auto getController(int player_id) -> int; // Obtiene el controlador asignado a un jugador + void initPlayers(Player::Id player_id); // Inicializa los datos de los jugadores + void updatePlayers(); // Actualiza las variables y estados de los jugadores + void renderPlayers(); // Renderiza todos los jugadores en pantalla + void sortPlayersByZOrder(); // Reorganiza el orden de dibujado de jugadores + auto getPlayer(Player::Id id) -> std::shared_ptr; // Obtiene un jugador por su identificador + static auto getController(Player::Id player_id) -> int; // Obtiene el controlador asignado a un jugador // --- Estado de jugadores --- void checkAndUpdatePlayerStatus(int active_player_index, int inactive_player_index); // Actualiza estado entre jugadores @@ -214,7 +211,7 @@ class Game { // --- Sistema de balas y proyectiles --- void updateBullets(); // Actualiza posición y estado de todas las balas void renderBullets(); // Renderiza todas las balas activas - void createBullet(int x, int y, BulletType kind, bool powered_up, int owner); // Crea una nueva bala + void createBullet(int x, int y, BulletType kind, bool powered_up, Player::Id owner); // Crea una nueva bala void checkBulletCollision(); // Verifica colisiones de todas las balas void freeBullets(); // Libera memoria del vector de balas @@ -276,7 +273,7 @@ class Game { void initScoreboard(); // Inicializa el sistema de puntuación // --- Modo demostración --- - void initDemo(int player_id); // Inicializa variables para el modo demostración + void initDemo(Player::Id player_id); // Inicializa variables para el modo demostración void updateDemo(); // Actualiza lógica específica del modo demo // --- Recursos y renderizado --- diff --git a/source/sections/hiscore_table.cpp b/source/sections/hiscore_table.cpp index f754fee..72a4f81 100644 --- a/source/sections/hiscore_table.cpp +++ b/source/sections/hiscore_table.cpp @@ -348,7 +348,7 @@ void HiScoreTable::iniEntryColors() { // Hace brillar los nombres de la tabla de records void HiScoreTable::glowEntryNames() { const Color ENTRY_COLOR = getEntryColor(counter_ / 5); - for (const auto &entry_index : Options::settings.last_hi_score_entry) { + for (const auto &entry_index : Options::settings.glowing_entries) { if (entry_index != -1) { entry_names_.at(entry_index)->getTexture()->setColor(ENTRY_COLOR); } diff --git a/source/sections/title.cpp b/source/sections/title.cpp index 1e8d2c5..5b9a683 100644 --- a/source/sections/title.cpp +++ b/source/sections/title.cpp @@ -44,7 +44,7 @@ Title::Title() game_logo_(std::make_unique(param.game.game_area.center_x, param.title.title_c_c_position)), mini_logo_sprite_(std::make_unique(Resource::get()->getTexture("logo_jailgames_mini.png"))), define_buttons_(std::make_unique()), - num_controllers_(Input::get()->getNumControllers()), + num_controllers_(Input::get()->getNumGamepads()), state_(TitleState::LOGO_ANIMATING) { // Configura objetos tiled_bg_->setColor(param.title.bg_color); @@ -213,12 +213,12 @@ void Title::printColorValue(const Color& color) { void Title::handleControlKeys(SDL_Keycode key) { switch (key) { case SDLK_1: - define_buttons_->enable(0); + define_buttons_->enable(Options::gamepads.at(0)); resetCounter(); break; case SDLK_2: - define_buttons_->enable(1); + define_buttons_->enable(Options::gamepads.at(1)); resetCounter(); break; @@ -262,29 +262,29 @@ auto Title::shouldSkipInputCheck() const -> bool { } void Title::processControllerInputs() { - for (const auto& controller : Options::controllers) { + for (const auto& controller : Options::gamepads) { if (isStartButtonPressed(controller)) { handleStartButtonPress(controller); } } } -auto Title::isStartButtonPressed(const Options::GamepadOptions& controller) -> bool { +auto Title::isStartButtonPressed(std::shared_ptr controller) -> bool { return Input::get()->checkAction( Input::Action::START, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD, - controller.gamepad); + controller->instance); } -void Title::handleStartButtonPress(const Options::GamepadOptions& controller) { +void Title::handleStartButtonPress(std::shared_ptr controller) { if (!canProcessStartButton()) { return; } - if (controller.player_id == 1) { + if (controller->player_id == Player::Id::PLAYER1) { processPlayer1Start(); - } else if (controller.player_id == 2) { + } else if (controller->player_id == Player::Id::PLAYER2) { processPlayer2Start(); } } @@ -296,18 +296,18 @@ auto Title::canProcessStartButton() const -> bool { void Title::processPlayer1Start() { if (!player1_start_pressed_) { player1_start_pressed_ = true; - activatePlayerAndSetState(1); + activatePlayerAndSetState(Player::Id::PLAYER1); } } void Title::processPlayer2Start() { if (!player2_start_pressed_) { player2_start_pressed_ = true; - activatePlayerAndSetState(2); + activatePlayerAndSetState(Player::Id::PLAYER2); } } -void Title::activatePlayerAndSetState(int player_id) { +void Title::activatePlayerAndSetState(Player::Id player_id) { getPlayer(player_id)->setPlayingState(Player::State::TITLE_ANIMATION); setState(TitleState::START_HAS_BEEN_PRESSED); counter_ = 0; @@ -328,7 +328,7 @@ void Title::resetCounter() { counter_ = 0; } // Intercambia la asignación de mandos a los jugadores void Title::swapControllers() { - if (Input::get()->getNumControllers() == 0) { + if (Input::get()->getNumGamepads() == 0) { return; } @@ -339,33 +339,34 @@ void Title::swapControllers() { // Intercambia el teclado de jugador void Title::swapKeyboard() { Options::swapKeyboard(); - std::string text = Lang::getText("[DEFINE_BUTTONS] PLAYER") + std::to_string(Options::getPlayerWhoUsesKeyboard()) + ": " + Lang::getText("[DEFINE_BUTTONS] KEYBOARD"); + std::string text = Lang::getText("[DEFINE_BUTTONS] PLAYER") + std::to_string(static_cast(Options::getPlayerWhoUsesKeyboard())) + ": " + Lang::getText("[DEFINE_BUTTONS] KEYBOARD"); Notifier::get()->show({text}); } // Muestra información sobre los controles y los jugadores void Title::showControllers() { - // Crea vectores de texto vacíos para un número máximo de mandos - constexpr size_t NUM_CONTROLLERS = 2; - std::vector text(NUM_CONTROLLERS); - std::vector player_controller_index(NUM_CONTROLLERS, -1); + /* // Crea vectores de texto vacíos para un número máximo de mandos + constexpr size_t NUM_CONTROLLERS = 2; + std::vector text(NUM_CONTROLLERS); + std::vector player_controller_index(NUM_CONTROLLERS, -1); - // Obtiene de cada jugador el índice del mando que tiene asignado - for (size_t i = 0; i < NUM_CONTROLLERS; ++i) { - // Ejemplo: el jugador 1 tiene el mando 2 - player_controller_index.at(Options::controllers.at(i).player_id - 1) = i; - } + // Obtiene de cada jugador el índice del mando que tiene asignado + for (size_t i = 0; i < NUM_CONTROLLERS; ++i) { + // Ejemplo: el jugador 1 tiene el mando 2 + player_controller_index.at(Options::controllers.at(i)->player_id - 1) = i; + } - // Genera el texto correspondiente - //for (size_t i = 0; i < NUM_CONTROLLERS; ++i) { - // const size_t INDEX = player_controller_index.at(i); - // if (Options::controllers.at(INDEX).plugged) { - // text.at(i) = Lang::getText("[DEFINE_BUTTONS] PLAYER") + std::to_string(i + 1) + ": " + Options::controllers.at(INDEX).name; - // } - //} + // Genera el texto correspondiente + for (size_t i = 0; i < NUM_CONTROLLERS; ++i) { + const size_t INDEX = player_controller_index.at(i); + if (Options::controllers.at(INDEX).plugged) { + text.at(i) = Lang::getText("[DEFINE_BUTTONS] PLAYER") + std::to_string(i + 1) + ": " + Options::controllers.at(INDEX).name; + } + } - // Muestra la notificación - Notifier::get()->show({text.at(0), text.at(1)}); + // Muestra la notificación + Notifier::get()->show({text.at(0), text.at(1)}); + */ } // Actualiza el fade @@ -558,10 +559,31 @@ void Title::initPlayers() { constexpr int PLAYER_HEIGHT = 32; const int Y = param.title.press_start_position - (PLAYER_HEIGHT / 2); constexpr bool DEMO = false; - players_.emplace_back(std::make_unique(1, param.game.game_area.center_x - (PLAYER_WIDTH / 2), Y, DEMO, param.game.play_area.rect, player_textures.at(0), player_animations)); + + Player::Config config_player1; + config_player1.id = Player::Id::PLAYER1; + config_player1.x = param.game.game_area.center_x - (PLAYER_WIDTH / 2); + config_player1.y = Y; + config_player1.demo = DEMO; + config_player1.play_area = ¶m.game.play_area.rect; + config_player1.texture = player_textures.at(0); + config_player1.animations = player_animations; + config_player1.hi_score_table = &Options::settings.hi_score_table; + config_player1.glowing_entry = &Options::settings.glowing_entries.at(static_cast(Player::Id::PLAYER1) - 1); + players_.emplace_back(std::make_unique(config_player1)); players_.back()->setPlayingState(Player::State::TITLE_HIDDEN); - players_.emplace_back(std::make_unique(2, param.game.game_area.center_x - (PLAYER_WIDTH / 2), Y, DEMO, param.game.play_area.rect, player_textures.at(1), player_animations)); + Player::Config config_player2; + config_player2.id = Player::Id::PLAYER2; + config_player2.x = param.game.game_area.center_x - (PLAYER_WIDTH / 2); + config_player2.y = Y; + config_player2.demo = DEMO; + config_player2.play_area = ¶m.game.play_area.rect; + config_player2.texture = player_textures.at(1); + config_player2.animations = player_animations; + config_player2.hi_score_table = &Options::settings.hi_score_table; + config_player2.glowing_entry = &Options::settings.glowing_entries.at(static_cast(Player::Id::PLAYER2) - 1); + players_.emplace_back(std::make_unique(config_player2)); players_.back()->setPlayingState(Player::State::TITLE_HIDDEN); } @@ -580,7 +602,7 @@ void Title::renderPlayers() { } // Obtiene un jugador a partir de su "id" -auto Title::getPlayer(int id) -> std::shared_ptr { +auto Title::getPlayer(Player::Id id) -> std::shared_ptr { auto it = std::find_if(players_.begin(), players_.end(), [id](const auto& player) { return player->getId() == id; }); if (it != players_.end()) { diff --git a/source/sections/title.h b/source/sections/title.h index 1c4017e..50e66ab 100644 --- a/source/sections/title.h +++ b/source/sections/title.h @@ -7,17 +7,17 @@ #include // Para string_view #include // Para vector +#include "player.h" // Para Player #include "section.hpp" // Para Options, Name (ptr only) class DefineButtons; class Fade; class GameLogo; -class Player; class Sprite; class Text; class TiledBG; namespace Options { -struct GamepadOptions; +struct Gamepad; } // namespace Options struct Color; @@ -87,24 +87,24 @@ class Title { void resetCounter(); // Reinicia el contador interno // --- Entrada de usuario --- - void checkEvents(); // Comprueba los eventos - void checkInput(); // Comprueba las entradas - void handleKeyDownEvent(const SDL_Event& event); // Maneja el evento de tecla presionada - void handleControlKeys(SDL_Keycode key); // Maneja las teclas de control específicas - [[nodiscard]] auto shouldSkipInputCheck() const -> bool; // Determina si se debe omitir la comprobación de entrada - void processControllerInputs(); // Procesa las entradas de los mandos - [[nodiscard]] static auto isStartButtonPressed(const Options::GamepadOptions& controller) -> bool; // Comprueba si se ha pulsado el botón Start - void handleStartButtonPress(const Options::GamepadOptions& controller); // Maneja la pulsación del botón Start - [[nodiscard]] auto canProcessStartButton() const -> bool; // Verifica si se puede procesar la pulsación del botón Start - void processPlayer1Start(); // Procesa el inicio del jugador 1 - void processPlayer2Start(); // Procesa el inicio del jugador 2 - void activatePlayerAndSetState(int player_id); // Activa al jugador y cambia el estado del título + void checkEvents(); // Comprueba los eventos + void checkInput(); // Comprueba las entradas + void handleKeyDownEvent(const SDL_Event& event); // Maneja el evento de tecla presionada + void handleControlKeys(SDL_Keycode key); // Maneja las teclas de control específicas + [[nodiscard]] auto shouldSkipInputCheck() const -> bool; // Determina si se debe omitir la comprobación de entrada + void processControllerInputs(); // Procesa las entradas de los mandos + [[nodiscard]] static auto isStartButtonPressed(std::shared_ptr controller) -> bool; // Comprueba si se ha pulsado el botón Start + void handleStartButtonPress(std::shared_ptr controller); // Maneja la pulsación del botón Start + [[nodiscard]] auto canProcessStartButton() const -> bool; // Verifica si se puede procesar la pulsación del botón Start + void processPlayer1Start(); // Procesa el inicio del jugador 1 + void processPlayer2Start(); // Procesa el inicio del jugador 2 + void activatePlayerAndSetState(Player::Id player_id); // Activa al jugador y cambia el estado del título // --- Gestión de jugadores --- - void initPlayers(); // Inicializa los jugadores - void updatePlayers(); // Actualiza los jugadores - void renderPlayers(); // Renderiza los jugadores - auto getPlayer(int id) -> std::shared_ptr; // Obtiene un jugador a partir de su "id" + void initPlayers(); // Inicializa los jugadores + void updatePlayers(); // Actualiza los jugadores + void renderPlayers(); // Renderiza los jugadores + auto getPlayer(Player::Id id) -> std::shared_ptr; // Obtiene un jugador a partir de su "id" // --- Visualización / Renderizado --- void render(); // Dibuja el objeto en pantalla