migrant input: commit abans que gemini destroçe algo

This commit is contained in:
2025-08-04 11:37:46 +02:00
parent 90c080f3e3
commit 050b6716bf
10 changed files with 245 additions and 99 deletions

View File

@@ -12,11 +12,12 @@
// Constructor
DefineButtons::DefineButtons()
: input_(Input::get()) {
// Inicializa variables
x_ = param.game.width / 2;
y_ = param.title.press_start_position;
: input_(Input::get()),
enabled_(false),
finished_(false),
x_(param.game.width / 2),
y_(param.title.press_start_position),
index_button_(0) {
clearButtons();
auto gamepads = input_->getGamepads();
@@ -29,8 +30,8 @@ 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(static_cast<int>(gamepad_options_->player_id)));
text->writeCentered(x_, y_, gamepad_options_->instance->name);
text->writeCentered(x_, y_ - 10, Lang::getText("[DEFINE_BUTTONS] PLAYER") + std::to_string(static_cast<int>(gamepad_->player_id)));
text->writeCentered(x_, y_, gamepad_->name);
text->writeCentered(x_, y_ + 10, buttons_.at(index_button_).label);
}
}
@@ -77,9 +78,9 @@ void DefineButtons::checkEvents(const SDL_Event &event) {
}
// Habilita el objeto
auto DefineButtons::enable(std::shared_ptr<Options::Gamepad> gamepad_options) -> bool {
if (gamepad_options != nullptr) {
gamepad_options_ = gamepad_options;
auto DefineButtons::enable(Options::Gamepad *gamepad) -> bool {
if (gamepad != nullptr) {
gamepad_ = gamepad;
enabled_ = true;
finished_ = false;
index_button_ = 0;

View File

@@ -27,10 +27,10 @@ class DefineButtons {
DefineButtons();
~DefineButtons() = default;
void render(); // Dibuja el objeto en pantalla
void checkEvents(const SDL_Event &event); // Procesa los eventos
auto enable(std::shared_ptr<Options::Gamepad> gamepad_options) -> 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(Options::Gamepad *gamepad) -> bool; // Habilita la redefinición de botones
[[nodiscard]] auto isEnabled() const -> bool { return enabled_; }; // Comprueba si está habilitado
private:
// Objetos
@@ -38,12 +38,13 @@ class DefineButtons {
// Variables
bool enabled_ = false; // Indica si está activo
int x_ = 0, y_ = 0; // Coordenadas de texto
bool finished_ = false; // Indica si ha terminado
int x_ = 0; // Coordenadas de texto
int y_ = 0; // Coordenadas de texto
std::vector<Button> buttons_; // Definiciones de botones
size_t index_button_ = 0; // Índice del botón en proceso
std::vector<std::string> controller_names_; // Nombres de los mandos
bool finished_ = false;
std::shared_ptr<Options::Gamepad> gamepad_options_;
Options::Gamepad *gamepad_;
// Métodos internos
void incIndexButton(); // Incrementa el índice de botones

View File

@@ -84,6 +84,11 @@ void Director::init() {
// Configuración inicial de parametros
Asset::init(executable_path_); // Inicializa el sistema de gestión de archivos
setFileList(); // Crea el índice de archivos
Input::init(
Asset::get()->get("gamecontrollerdb.txt"),
Asset::get()->get("controllers.json")); // Carga configuración de controles
Options::setConfigFile(Asset::get()->get("config.txt")); // Establece el fichero de configuración
Options::setControllersFile(Asset::get()->get("controllers.json")); // Establece el fichero de configuración de mandos
Options::loadFromFile(); // Carga el archivo de configuración
@@ -95,14 +100,7 @@ void Director::init() {
Screen::init(); // Inicializa la pantalla y el sistema de renderizado
Audio::init(); // Activa el sistema de audio
Resource::init(); // Inicializa el sistema de gestión de recursos
Input::init(
Asset::get()->get("gamecontrollerdb.txt"),
Asset::get()->get("controllers.json")); // Carga configuración de controles
bindInputs(); // Asigna los controles a la entrada del sistema
auto gamepads = Input::get()->getGamepads();
if (!gamepads.empty())
Options::gamepads.front()->instance = gamepads.front();
//bindInputs(); // Asigna los controles a la entrada del sistema
ServiceMenu::init(); // Inicializa el menú de servicio
Notifier::init(std::string(), Resource::get()->getText("8bithud")); // Inicialización del sistema de notificaciones

View File

@@ -435,4 +435,29 @@ bool Input::removeGamepadConfig(const std::string &gamepadName) {
}
return false;
}
std::shared_ptr<Input::Gamepad> Input::findAvailableGamepadByName(const std::string &gamepad_name)
{
// Si no hay gamepads disponibles, devolver gamepad por defecto
if (gamepads_.empty()) {
return nullptr;
}
// Buscar por nombre
for (const auto& gamepad : gamepads_) {
if (gamepad && gamepad->name == gamepad_name) {
return gamepad;
}
}
// Si no se encuentra por nombre, devolver el primer gamepad válido
for (const auto& gamepad : gamepads_) {
if (gamepad) {
return gamepad;
}
}
// Si llegamos aquí, no hay gamepads válidos
return nullptr;
}

View File

@@ -11,10 +11,6 @@
#include "gamepad_config_manager.h"
#include "input_types.h"
// Forward declaration para evitar dependencia circular
// struct GamepadConfig;
// class GamepadConfigManager;
// Clase Input: gestiona la entrada de teclado y mandos (singleton)
class Input {
public:
@@ -166,6 +162,7 @@ class Input {
void printConnectedGamepads() const;
[[nodiscard]] auto getGamepads() const -> const std::vector<std::shared_ptr<Gamepad>> & { return gamepads_; }
std::shared_ptr<Gamepad> findAvailableGamepadByName(const std::string &gamepad_name);
private:
// --- Constantes ---

View File

@@ -19,13 +19,13 @@
namespace Options {
// --- Variables globales ---
Window window; // Opciones de la ventana
Settings settings; // Opciones del juego
Video video; // Opciones de vídeo
Audio audio; // Opciones de audio
std::vector<std::shared_ptr<Gamepad>> gamepads; // Opciones de mando para cada jugador
Keyboard keyboard; // Opciones para el teclado
PendingChanges pending_changes; // Opciones que se aplican al cerrar
Window window; // Opciones de la ventana
Settings settings; // Opciones del juego
Video video; // Opciones de vídeo
Audio audio; // Opciones de audio
GamepadManager 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,9 +42,9 @@ void init() {
Difficulty::init();
// Opciones de control
gamepads.clear();
gamepads.emplace_back(std::make_shared<Gamepad>(Player::Id::PLAYER1));
gamepads.emplace_back(std::make_shared<Gamepad>(Player::Id::PLAYER2));
gamepads.init();
assignGamepadByName("", Player::Id::PLAYER1);
//assignGamepadByName("", Player::Id::PLAYER2);
setKeyboardToPlayer(Player::Id::PLAYER1);
// Opciones de cambios pendientes
@@ -153,16 +153,7 @@ auto saveToFile() -> bool {
// Opciones de mandos
file << "\n\n## CONTROLLERS\n";
// 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;
// }
gamepads.saveToFile(file);
// Cierra el fichero
file.close();
@@ -172,20 +163,21 @@ 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 = 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);
// }
size_t first_dot = var.find('.');
size_t second_dot = var.find('.', first_dot + 1);
if (first_dot == std::string::npos || second_dot == std::string::npos) {
return; // Formato inválido
}
try {
int controller_index = std::stoi(var.substr(first_dot + 1, second_dot - first_dot - 1));
std::string setting_key = var.substr(second_dot + 1);
gamepads.setControllerProperty(controller_index, setting_key, value);
} catch (const std::exception&) {
// Error en parsing
}
}
auto set(const std::string& var, const std::string& value) -> bool {
@@ -265,7 +257,7 @@ void swapKeyboard() {
// Intercambia los jugadores asignados a los dos primeros mandos
void swapControllers() {
std::swap(gamepads.at(0)->player_id, gamepads.at(1)->player_id);
gamepads.swapPlayers();
}
// Averigua quien está usando el teclado
@@ -286,4 +278,26 @@ void checkPendingChanges() {
pending_changes.has_pending_changes = settings.language != pending_changes.new_language ||
settings.difficulty != pending_changes.new_difficulty;
}
// Buscar y asignar un mando disponible por nombre
bool assignGamepadByName(const std::string& gamepad_name, Player::Id player_id) {
auto available_gamepad = Input::get()->findAvailableGamepadByName(gamepad_name);
if (available_gamepad) {
const std::string& actual_gamepad_name = available_gamepad->name;
return gamepads.assignGamepadToPlayer(player_id, available_gamepad, actual_gamepad_name);
}
return false;
}
// Obtener información de un gamepad específico
std::string getGamepadInfo(Player::Id player_id) {
try {
const auto& gamepad = gamepads.getGamepad(player_id);
return "Player " + std::to_string(static_cast<int>(player_id)) +
": " + (gamepad.name.empty() ? "No gamepad" : gamepad.name);
} catch (const std::exception&) {
return "Invalid player";
}
}
} // namespace Options

View File

@@ -4,6 +4,8 @@
#include <algorithm> // Para copy
#include <array> // Para array
#include <fstream> // Para ofstream
#include <stdexcept> // Para excepciones
#include <string> // Para allocator, string
#include <unordered_map>
#include <vector> // Para vector
@@ -15,6 +17,7 @@
#include "player.h" // Para Player
namespace Options {
// --- Opciones de ventana ---
struct Window {
std::string caption; // Texto que aparece en la barra de título de la ventana
@@ -90,6 +93,7 @@ struct Settings {
}
};
// --- Estructura para gamepad individual ---
struct Gamepad {
std::shared_ptr<Input::Gamepad> instance = nullptr; // Referencia al mando
std::string name; // Nombre del mando
@@ -99,6 +103,114 @@ struct Gamepad {
: player_id(custom_player_id) {}
};
// --- Manager para los gamepads ---
class GamepadManager {
private:
static constexpr size_t MAX_PLAYERS = 2;
std::array<Gamepad, MAX_PLAYERS> gamepads;
// Convierte Player::Id a índice del array
size_t playerIdToIndex(Player::Id player_id) const {
switch (player_id) {
case Player::Id::PLAYER1:
return 0;
case Player::Id::PLAYER2:
return 1;
default:
throw std::invalid_argument("Invalid player ID");
}
}
public:
void init() {
gamepads[0] = Gamepad(Player::Id::PLAYER1);
gamepads[1] = Gamepad(Player::Id::PLAYER2);
}
// Acceso directo por player_id (más intuitivo)
Gamepad& getGamepad(Player::Id player_id) {
return gamepads[playerIdToIndex(player_id)];
}
const Gamepad& getGamepad(Player::Id player_id) const {
return gamepads[playerIdToIndex(player_id)];
}
// Acceso por índice (más eficiente si ya tienes el índice)
Gamepad& operator[](size_t index) {
if (index >= MAX_PLAYERS) throw std::out_of_range("Invalid gamepad index");
return gamepads[index];
}
const Gamepad& operator[](size_t index) const {
if (index >= MAX_PLAYERS) throw std::out_of_range("Invalid gamepad index");
return gamepads[index];
}
bool assignGamepadToPlayer(Player::Id player_id,
std::shared_ptr<Input::Gamepad> instance,
const std::string& name) {
try {
auto& gamepad = getGamepad(player_id);
gamepad.instance = instance;
gamepad.name = name;
return true;
} catch (const std::exception&) {
return false;
}
}
void swapPlayers() {
std::swap(gamepads[0].player_id, gamepads[1].player_id);
}
// Para serialización/deserialización
void saveToFile(std::ofstream& file) const {
for (size_t i = 0; i < MAX_PLAYERS; ++i) {
const auto& gamepad = gamepads[i];
file << "controller." << i << ".name=" << gamepad.name << "\n";
file << "controller." << i << ".player=" << static_cast<int>(gamepad.player_id) << "\n";
}
}
// Método helper para parseAndSetController
bool setControllerProperty(size_t controller_index,
const std::string& property,
const std::string& value) {
if (controller_index >= MAX_PLAYERS) return false;
auto& gamepad = gamepads[controller_index];
if (property == "name") {
gamepad.name = value;
return true;
} else if (property == "player") {
try {
int player_int = std::stoi(value);
if (player_int == 1)
gamepad.player_id = Player::Id::PLAYER1;
else if (player_int == 2)
gamepad.player_id = Player::Id::PLAYER2;
else
return false;
return true;
} catch (const std::exception&) {
return false;
}
}
return false;
}
// Iteradores
auto begin() { return gamepads.begin(); }
auto end() { return gamepads.end(); }
auto begin() const { return gamepads.begin(); }
auto end() const { return gamepads.end(); }
size_t size() const { return MAX_PLAYERS; }
};
struct Keyboard {
Player::Id player_id = Player::Id::PLAYER1; // Jugador asociado al teclado
};
@@ -114,25 +226,25 @@ struct PendingChanges {
};
// --- Variables globales ---
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<std::shared_ptr<Gamepad>> gamepads; // Opciones de mando para cada jugador
extern Keyboard keyboard; // Opciones para el teclado
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 GamepadManager gamepads; // Manager de mandos 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
void setConfigFile(const std::string &file_path); // Establece el fichero de configuración
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(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() -> 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
void init(); // Inicializa las opciones del programa
void setConfigFile(const std::string& file_path); // Establece el fichero de configuración
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(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() -> 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
bool assignGamepadByName(const std::string& gamepad_name, Player::Id player_id); // Buscar y asignar un mando disponible por nombre
} // namespace Options

View File

@@ -1217,13 +1217,11 @@ auto Game::getPlayer(Player::Id id) -> std::shared_ptr<Player> {
// Obtiene un controlador a partir del "id" del jugador
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::gamepads.end()) {
return std::distance(Options::gamepads.begin(), it);
switch (player_id) {
case Player::Id::PLAYER1: return 0;
case Player::Id::PLAYER2: return 1;
default: return -1;
}
return -1;
}
// Gestiona la entrada durante el juego
@@ -1599,7 +1597,7 @@ void Game::initPlayers(Player::Id player_id) {
auto player1 = std::make_unique<Player>(config_player1);
player1->setScoreBoardPanel(Scoreboard::Id::LEFT);
player1->setName(Lang::getText("[SCOREBOARD] 1"));
player1->setGamepad(Options::gamepads.front()->instance);
player1->setGamepad(Options::gamepads.getGamepad(Player::Id::PLAYER1).instance);
player1->setUsesKeyboard(Player::Id::PLAYER1 == Options::keyboard.player_id);
player1->setPlayingState(Player::State::WAITING);
players_.push_back(std::move(player1));
@@ -1619,7 +1617,7 @@ void Game::initPlayers(Player::Id player_id) {
auto player2 = std::make_unique<Player>(config_player2);
player2->setScoreBoardPanel(Scoreboard::Id::RIGHT);
player2->setName(Lang::getText("[SCOREBOARD] 2"));
player2->setGamepad(Options::gamepads.back()->instance);
player2->setGamepad(Options::gamepads.getGamepad(Player::Id::PLAYER2).instance);
player2->setUsesKeyboard(Player::Id::PLAYER2 == Options::keyboard.player_id);
player2->setPlayingState(Player::State::WAITING);
players_.push_back(std::move(player2));

View File

@@ -213,12 +213,12 @@ void Title::printColorValue(const Color& color) {
void Title::handleControlKeys(SDL_Keycode key) {
switch (key) {
case SDLK_1:
define_buttons_->enable(Options::gamepads.at(0));
define_buttons_->enable(&Options::gamepads.getGamepad(Player::Id::PLAYER1));
resetCounter();
break;
case SDLK_2:
define_buttons_->enable(Options::gamepads.at(1));
define_buttons_->enable(&Options::gamepads.getGamepad(Player::Id::PLAYER2));
resetCounter();
break;
@@ -263,13 +263,13 @@ auto Title::shouldSkipInputCheck() const -> bool {
void Title::processControllerInputs() {
for (const auto& controller : Options::gamepads) {
if (isStartButtonPressed(controller)) {
handleStartButtonPress(controller);
if (isStartButtonPressed(&controller)) {
handleStartButtonPress(&controller);
}
}
}
auto Title::isStartButtonPressed(std::shared_ptr<Options::Gamepad> controller) -> bool {
auto Title::isStartButtonPressed(const Options::Gamepad *controller) -> bool {
return Input::get()->checkAction(
Input::Action::START,
Input::DO_NOT_ALLOW_REPEAT,
@@ -277,7 +277,7 @@ auto Title::isStartButtonPressed(std::shared_ptr<Options::Gamepad> controller) -
controller->instance);
}
void Title::handleStartButtonPress(std::shared_ptr<Options::Gamepad> controller) {
void Title::handleStartButtonPress(const Options::Gamepad *controller) {
if (!canProcessStartButton()) {
return;
}

View File

@@ -93,8 +93,8 @@ class Title {
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<Options::Gamepad> controller) -> bool; // Comprueba si se ha pulsado el botón Start
void handleStartButtonPress(std::shared_ptr<Options::Gamepad> controller); // Maneja la pulsación del botón Start
[[nodiscard]] static auto isStartButtonPressed(const Options::Gamepad *controller) -> bool; // Comprueba si se ha pulsado el botón Start
void handleStartButtonPress(const Options::Gamepad *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