diff --git a/.claude/commands/refactor-class.md b/.claude/commands/refactor-class.md new file mode 100644 index 0000000..f1f1d2d --- /dev/null +++ b/.claude/commands/refactor-class.md @@ -0,0 +1,171 @@ +--- +description: Refactoriza una clase C++ aplicando buenas prácticas de estilo +--- + +# Refactor Class Command + +Refactoriza una clase C++ siguiendo estas reglas de estilo y buenas prácticas: + +## Reglas de Refactorización + +### 1. Inicialización de Variables Miembro +- **Inicializar en la declaración** todas las variables "simples" que no tengan dependencias complejas: + - Tipos primitivos: `int`, `float`, `bool`, etc. + - Enumeraciones: valores de enum class + - Valores por defecto conocidos: `0`, `0.0F`, `false`, `nullptr`, etc. +- **NO inicializar en declaración** si: + - Dependen de otros miembros + - Requieren llamadas a funciones complejas + - Son punteros a recursos que necesitan construcción específica + +### 2. Structs con Valores por Defecto +- **Todos los miembros de structs** deben tener valores por defecto: + - Tipos primitivos: `int x{0}`, `float y{0.0F}`, `bool flag{false}` + - Strings: `std::string name{}` + - Punteros: `Type* ptr{nullptr}` +- **Ventajas**: Inicialización segura, evita valores indefinidos + +### 3. Arrays C-style → std::array +- Convertir **todos** los arrays C-style a `std::array`: + - `Type array[N]` → `std::array array{}` + - Inicializar con `{}` para zero-initialization +- Agregar `#include ` si no existe +- **Ventajas**: type-safety, size(), métodos STL, sin decay a pointer + +### 3. Reorganización de la Clase + +#### Orden de Secciones +1. **public** (primero) +2. **private** (después) + +#### Dentro de cada sección (private principalmente) +1. **Estructuras y enumeraciones** (tipos anidados) +2. **Constantes** (static constexpr) +3. **Métodos** (funciones miembro) +4. **Variables miembro** (al final) + +### 4. Agrupación y Comentarios de Métodos +- **En sección public**: Agrupar métodos relacionados funcionalmente +- **Comentarios en línea** (a la derecha) para describir cada método/grupo +- **Formato**: `void method(); // Descripción concisa` +- **Espaciado**: Línea en blanco entre grupos funcionales + +**Ejemplo:** +```cpp +public: + static void init(...); // Inicialización singleton + static void destroy(); // Destrucción singleton + static auto get() -> T*; // Acceso al singleton + + void render(); // Renderizado + void update(float dt); // Actualización lógica + + auto isActive() -> bool; // Consulta estado +``` + +### 5. Comentarios de Variables +- **Posición**: A la derecha de la variable/grupo +- **Formato**: `// Descripción concisa` +- Agrupar variables relacionadas con un comentario común + +### 6. Constructores en Structs +- **Eliminar constructores por defecto redundantes** en structs: + - Si todos los miembros tienen inicialización en declaración + - Y no hay múltiples constructores + - Eliminar `explicit Type() = default;` +- El compilador generará automáticamente un constructor por defecto + +**Ejemplo:** +```cpp +struct Data { + int x{0}; + std::string name{}; + // NO NECESITA: explicit Data() = default; +}; +``` + +### 7. Includes Necesarios +- Agregar includes faltantes según lo que se use +- Mantener orden alfabético si es posible + +### 8. Header Guards +- **Usar `#pragma once`** en todas las cabeceras (`.hpp`) +- **NO usar** `#ifndef`/`#define`/`#endif` tradicionales +- `#pragma once` debe ser la primera línea del archivo (antes de includes) +- **Ventajas**: Más simple, menos propenso a errores, ampliamente soportado + +## Ejemplo de Aplicación + +### Antes: +```cpp +class Example { + private: + struct Data { + std::string name; + int value; + }; + + int counter_; + bool flag_; + float values_[10]; + + public: + Example(); + void update(); +}; + +// Constructor +Example::Example() + : counter_(0), + flag_(false) { + for (int i = 0; i < 10; ++i) { + values_[i] = 0.0F; + } +} +``` + +### Después: +```cpp +#pragma once + +#include + +class Example { + public: + Example() = default; // Ya no necesita inicializar + void update(); + + private: + // Tipos anidados + struct Data { + std::string name{}; // Nombre con valor por defecto + int value{0}; // Valor inicializado + }; + + // Variables miembro + int counter_{0}; // Contador de frames + bool flag_{false}; // Estado activo + std::array values_{}; // Buffer de valores +}; +``` + +## Tareas a Realizar + +Cuando uses este comando en una clase específica: + +1. **Leer** el archivo `.hpp` y `.cpp` correspondiente +2. **Verificar** que la cabecera use `#pragma once` (reemplazar `#ifndef`/`#define`/`#endif` si existen) +3. **Identificar** structs y agregar valores por defecto a todos sus miembros +4. **Identificar** variables que pueden inicializarse en declaración +5. **Identificar** arrays C-style que convertir a std::array +6. **Reorganizar** la estructura de la clase (public/private, agrupación) +7. **Actualizar** el archivo `.cpp` eliminando inicializaciones redundantes +8. **Verificar** que compile correctamente +9. **Informar** al usuario de los cambios realizados + +## Notas Importantes + +- **No cambiar lógica**: Solo refactorización estructural +- **Mantener compatibilidad**: std::array usa misma sintaxis [] para acceso +- **Formato consistente**: Respetar estilo del proyecto (comentarios, espaciado) +- **Validar compilación**: Siempre verificar que compile después de cambios diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..04d6a79 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,9 @@ +{ + "permissions": { + "allow": [ + "Bash(cmake --build:*)" + ], + "deny": [], + "ask": [] + } +} diff --git a/.gitignore b/.gitignore index fc4aa31..8b44f29 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,6 @@ jaildoctors_dilemma* todo build/ linux_utils/ -.claude/ source/version.h resources.pack jdd_release/ diff --git a/source/core/audio/audio.hpp b/source/core/audio/audio.hpp index e2dab7a..78597f3 100644 --- a/source/core/audio/audio.hpp +++ b/source/core/audio/audio.hpp @@ -24,87 +24,74 @@ class Audio { static constexpr float MIN_VOLUME = 0.0F; // Volumen mínimo static constexpr int FREQUENCY = 48000; // Frecuencia de audio - // --- Métodos de singleton --- + // --- Singleton --- static void init(); // Inicializa el objeto Audio static void destroy(); // Libera el objeto Audio static auto get() -> Audio*; // Obtiene el puntero al objeto Audio Audio(const Audio&) = delete; // Evitar copia auto operator=(const Audio&) -> Audio& = delete; // Evitar asignación - // --- Método principal --- - static void update(); + static void update(); // Actualización del sistema de audio - // --- Control de Música --- + // --- Control de música --- void playMusic(const std::string& name, int loop = -1); // Reproducir música en bucle void pauseMusic(); // Pausar reproducción de música void resumeMusic(); // Continua la música pausada void stopMusic(); // Detener completamente la música void fadeOutMusic(int milliseconds) const; // Fundido de salida de la música - // --- Control de Sonidos --- + // --- Control de sonidos --- void playSound(const std::string& name, Group group = Group::GAME) const; // Reproducir sonido puntual por nombre void playSound(struct JA_Sound_t* sound, Group group = Group::GAME) const; // Reproducir sonido puntual por puntero void stopAllSounds() const; // Detener todos los sonidos - // --- Configuración General --- + // --- Control de volumen --- + void setSoundVolume(float volume, Group group = Group::ALL) const; // Ajustar volumen de efectos + void setMusicVolume(float volume) const; // Ajustar volumen de música + + // --- Configuración general --- void enable(bool value); // Establecer estado general void toggleEnabled() { enabled_ = !enabled_; } // Alternar estado general void applySettings(); // Aplica la configuración - // --- Configuración de Sonidos --- + // --- Configuración de sonidos --- void enableSound() { sound_enabled_ = true; } // Habilitar sonidos void disableSound() { sound_enabled_ = false; } // Deshabilitar sonidos void enableSound(bool value) { sound_enabled_ = value; } // Establecer estado de sonidos void toggleSound() { sound_enabled_ = !sound_enabled_; } // Alternar estado de sonidos - // --- Configuración de Música --- + // --- Configuración de música --- void enableMusic() { music_enabled_ = true; } // Habilitar música void disableMusic() { music_enabled_ = false; } // Deshabilitar música void enableMusic(bool value) { music_enabled_ = value; } // Establecer estado de música void toggleMusic() { music_enabled_ = !music_enabled_; } // Alternar estado de música - // --- Control de Volumen --- - void setSoundVolume(float volume, Group group = Group::ALL) const; // Ajustar volumen de efectos - void setMusicVolume(float volume) const; // Ajustar volumen de música - - // --- Getters para debug --- + // --- Consultas de estado --- [[nodiscard]] auto isEnabled() const -> bool { return enabled_; } [[nodiscard]] auto isSoundEnabled() const -> bool { return sound_enabled_; } [[nodiscard]] auto isMusicEnabled() const -> bool { return music_enabled_; } [[nodiscard]] auto getMusicState() const -> MusicState { return music_.state; } - [[nodiscard]] static auto getRealMusicState() -> MusicState; // Consulta directamente a jailaudio + [[nodiscard]] static auto getRealMusicState() -> MusicState; [[nodiscard]] auto getCurrentMusicName() const -> const std::string& { return music_.name; } private: - // --- Estructuras privadas --- + // --- Tipos anidados --- struct Music { - MusicState state{MusicState::STOPPED}; // Estado actual de la música (reproduciendo, detenido, en pausa) - std::string name; // Última pista de música reproducida - bool loop{false}; // Indica si la última pista de música se debe reproducir en bucle - - // Constructor para inicializar la música con valores predeterminados - Music() = default; - - // Constructor para inicializar con valores específicos - Music(MusicState init_state, std::string init_name, bool init_loop) - : state(init_state), - name(std::move(init_name)), - loop(init_loop) {} + MusicState state{MusicState::STOPPED}; // Estado actual de la música + std::string name{}; // Última pista de música reproducida + bool loop{false}; // Indica si se reproduce en bucle }; - // --- Variables de estado --- - Music music_; // Estado de la música - bool enabled_ = true; // Estado general del audio - bool sound_enabled_ = true; // Estado de los efectos de sonido - bool music_enabled_ = true; // Estado de la música - - // --- Métodos internos --- + // --- Métodos --- + Audio(); // Constructor privado + ~Audio(); // Destructor privado void initSDLAudio(); // Inicializa SDL Audio - // --- Constructores y destructor privados (singleton) --- - Audio(); // Constructor privado - ~Audio(); // Destructor privado - - // --- Instancia singleton --- + // --- Variables miembro --- static Audio* instance; // Instancia única de Audio + + Music music_; // Estado de la música + bool enabled_{true}; // Estado general del audio + bool sound_enabled_{true}; // Estado de los efectos de sonido + bool music_enabled_{true}; // Estado de la música }; \ No newline at end of file diff --git a/source/core/input/input.cpp b/source/core/input/input.cpp index 26acc51..95c1b96 100644 --- a/source/core/input/input.cpp +++ b/source/core/input/input.cpp @@ -28,6 +28,33 @@ auto Input::get() -> Input* { return Input::instance; } Input::Input(std::string game_controller_db_path, std::string gamepad_configs_file) : gamepad_mappings_file_(std::move(game_controller_db_path)), gamepad_configs_file_(std::move(gamepad_configs_file)) { + // Inicializar bindings del teclado + keyboard_.bindings = { + // Movimiento del jugador + {Action::LEFT, KeyState{SDL_SCANCODE_LEFT}}, + {Action::RIGHT, KeyState{SDL_SCANCODE_RIGHT}}, + {Action::JUMP, KeyState{SDL_SCANCODE_UP}}, + + // Inputs de control + {Action::ACCEPT, KeyState{SDL_SCANCODE_RETURN}}, + {Action::CANCEL, KeyState{SDL_SCANCODE_ESCAPE}}, + {Action::EXIT, KeyState{SDL_SCANCODE_ESCAPE}}, + + // Inputs de sistema + {Action::WINDOW_DEC_ZOOM, KeyState{SDL_SCANCODE_F1}}, + {Action::WINDOW_INC_ZOOM, KeyState{SDL_SCANCODE_F2}}, + {Action::TOGGLE_FULLSCREEN, KeyState{SDL_SCANCODE_F3}}, + {Action::TOGGLE_SHADERS, KeyState{SDL_SCANCODE_F4}}, + {Action::NEXT_PALETTE, KeyState{SDL_SCANCODE_F5}}, + {Action::PREVIOUS_PALETTE, KeyState{SDL_SCANCODE_F6}}, + {Action::TOGGLE_INTEGER_SCALE, KeyState{SDL_SCANCODE_F7}}, + {Action::TOGGLE_MUSIC, KeyState{SDL_SCANCODE_F8}}, + {Action::TOGGLE_BORDER, KeyState{SDL_SCANCODE_F9}}, + {Action::TOGGLE_VSYNC, KeyState{SDL_SCANCODE_F10}}, + {Action::TOGGLE_DEBUG, KeyState{SDL_SCANCODE_F12}}, + {Action::SHOW_DEBUG_INFO, KeyState{SDL_SCANCODE_F11}} + }; + initSDLGamePad(); // Inicializa el subsistema SDL_INIT_GAMEPAD } diff --git a/source/core/input/input.hpp b/source/core/input/input.hpp index 1f8ba64..bd356e3 100644 --- a/source/core/input/input.hpp +++ b/source/core/input/input.hpp @@ -28,148 +28,103 @@ class Input { // --- Estructuras --- struct KeyState { - Uint8 scancode; // Scancode asociado - bool is_held; // Está pulsada ahora mismo - bool just_pressed; // Se acaba de pulsar en este fotograma - - KeyState(Uint8 scancode = 0, bool is_held = false, bool just_pressed = false) - : scancode(scancode), - is_held(is_held), - just_pressed(just_pressed) {} + Uint8 scancode{0}; // Scancode asociado + bool is_held{false}; // Está pulsada ahora mismo + bool just_pressed{false}; // Se acaba de pulsar en este fotograma }; struct ButtonState { - int button; // GameControllerButton asociado - bool is_held; // Está pulsada ahora mismo - bool just_pressed; // Se acaba de pulsar en este fotograma - bool axis_active; // Estado del eje - bool trigger_active{false}; // Estado del trigger como botón digital - - ButtonState(int btn = static_cast(SDL_GAMEPAD_BUTTON_INVALID), bool is_held = false, bool just_pressed = false, bool axis_act = false) - : button(btn), - is_held(is_held), - just_pressed(just_pressed), - axis_active(axis_act) {} + int button{static_cast(SDL_GAMEPAD_BUTTON_INVALID)}; // GameControllerButton asociado + bool is_held{false}; // Está pulsada ahora mismo + bool just_pressed{false}; // Se acaba de pulsar en este fotograma + bool axis_active{false}; // Estado del eje + bool trigger_active{false}; // Estado del trigger como botón digital }; struct Keyboard { - std::unordered_map bindings; - - Keyboard() - : bindings{ - // Movimiento del jugador - {Action::LEFT, KeyState(SDL_SCANCODE_LEFT)}, - {Action::RIGHT, KeyState(SDL_SCANCODE_RIGHT)}, - {Action::JUMP, KeyState(SDL_SCANCODE_UP)}, - - // Inputs de control - {Action::ACCEPT, KeyState(SDL_SCANCODE_RETURN)}, - {Action::CANCEL, KeyState(SDL_SCANCODE_ESCAPE)}, - {Action::EXIT, KeyState(SDL_SCANCODE_ESCAPE)}, - - // Inputs de sistema - {Action::WINDOW_DEC_ZOOM, KeyState(SDL_SCANCODE_F1)}, - {Action::WINDOW_INC_ZOOM, KeyState(SDL_SCANCODE_F2)}, - {Action::TOGGLE_FULLSCREEN, KeyState(SDL_SCANCODE_F3)}, - {Action::TOGGLE_SHADERS, KeyState(SDL_SCANCODE_F4)}, - {Action::NEXT_PALETTE, KeyState(SDL_SCANCODE_F5)}, - {Action::PREVIOUS_PALETTE, KeyState(SDL_SCANCODE_F6)}, - {Action::TOGGLE_INTEGER_SCALE, KeyState(SDL_SCANCODE_F7)}, - {Action::TOGGLE_MUSIC, KeyState(SDL_SCANCODE_F8)}, - {Action::TOGGLE_BORDER, KeyState(SDL_SCANCODE_F9)}, - {Action::TOGGLE_VSYNC, KeyState(SDL_SCANCODE_F10)}, - {Action::TOGGLE_DEBUG, KeyState(SDL_SCANCODE_F12)}, - {Action::SHOW_DEBUG_INFO, KeyState(SDL_SCANCODE_F11)}} {} + std::unordered_map bindings{}; // Mapa de acciones a estados de tecla }; struct Gamepad { - SDL_Gamepad* pad; - SDL_JoystickID instance_id; - std::string name; - std::string path; - std::unordered_map bindings; + SDL_Gamepad* pad{nullptr}; // Puntero al gamepad SDL + SDL_JoystickID instance_id{0}; // ID de instancia del joystick + std::string name{}; // Nombre del gamepad + std::string path{}; // Ruta del dispositivo + std::unordered_map bindings{}; // Mapa de acciones a estados de botón - explicit Gamepad(SDL_Gamepad* gamepad) - : pad(gamepad), - instance_id(SDL_GetJoystickID(SDL_GetGamepadJoystick(gamepad))), - name(std::string(SDL_GetGamepadName(gamepad))), - path(std::string(SDL_GetGamepadPath(pad))), - bindings{ - // Movimiento del jugador - {Action::LEFT, ButtonState(static_cast(SDL_GAMEPAD_BUTTON_DPAD_LEFT))}, - {Action::RIGHT, ButtonState(static_cast(SDL_GAMEPAD_BUTTON_DPAD_RIGHT))}, - {Action::JUMP, ButtonState(static_cast(SDL_GAMEPAD_BUTTON_WEST))}} {} + explicit Gamepad(SDL_Gamepad* gamepad) + : pad(gamepad), + instance_id(SDL_GetJoystickID(SDL_GetGamepadJoystick(gamepad))), + name(std::string(SDL_GetGamepadName(gamepad))), + path(std::string(SDL_GetGamepadPath(pad))), + bindings{ + // Movimiento del jugador + {Action::LEFT, ButtonState{static_cast(SDL_GAMEPAD_BUTTON_DPAD_LEFT)}}, + {Action::RIGHT, ButtonState{static_cast(SDL_GAMEPAD_BUTTON_DPAD_RIGHT)}}, + {Action::JUMP, ButtonState{static_cast(SDL_GAMEPAD_BUTTON_WEST)}}} {} - ~Gamepad() { - if (pad != nullptr) { - SDL_CloseGamepad(pad); - } + ~Gamepad() { + if (pad != nullptr) { + SDL_CloseGamepad(pad); } + } - // Reasigna un botón a una acción - void rebindAction(Action action, SDL_GamepadButton new_button) { - bindings[action] = static_cast(new_button); - } + // Reasigna un botón a una acción + void rebindAction(Action action, SDL_GamepadButton new_button) { + bindings[action].button = static_cast(new_button); + } }; // --- Tipos --- using Gamepads = std::vector>; // Vector de gamepads - // --- Métodos de singleton --- + // --- Singleton --- static void init(const std::string& game_controller_db_path, const std::string& gamepad_configs_file); static void destroy(); static auto get() -> Input*; - // --- Métodos de configuración de controles --- + // --- Actualización del sistema --- + void update(); // Actualiza estados de entrada + + // --- Configuración de controles --- void bindKey(Action action, SDL_Scancode code); - void applyKeyboardBindingsFromOptions(); // Aplica las teclas configuradas desde Options - void applyGamepadBindingsFromOptions(); // Aplica los botones del gamepad configurados desde Options + void applyKeyboardBindingsFromOptions(); + void applyGamepadBindingsFromOptions(); static void bindGameControllerButton(const std::shared_ptr& gamepad, Action action, SDL_GamepadButton button); static void bindGameControllerButton(const std::shared_ptr& gamepad, Action action_target, Action action_source); - // --- Métodos de consulta de entrada --- - void update(); + // --- Consulta de entrada --- auto checkAction(Action action, bool repeat = true, bool check_keyboard = true, const std::shared_ptr& gamepad = nullptr) -> bool; auto checkAnyInput(bool check_keyboard = true, const std::shared_ptr& gamepad = nullptr) -> bool; auto checkAnyButton(bool repeat = DO_NOT_ALLOW_REPEAT) -> bool; + void resetInputStates(); - // --- Métodos de gestión de mandos --- + // --- Gestión de gamepads --- [[nodiscard]] auto gameControllerFound() const -> bool; - static auto getControllerName(const std::shared_ptr& gamepad) -> std::string; - auto getControllerNames() const -> std::vector; [[nodiscard]] auto getNumGamepads() const -> int; auto getGamepad(SDL_JoystickID id) const -> std::shared_ptr; auto getGamepadByName(const std::string& name) const -> std::shared_ptr; auto getGamepads() const -> const Gamepads& { return gamepads_; } - - // --- Métodos de consulta y utilidades --- + auto findAvailableGamepadByName(const std::string& gamepad_name) -> std::shared_ptr; + static auto getControllerName(const std::shared_ptr& gamepad) -> std::string; + auto getControllerNames() const -> std::vector; [[nodiscard]] static auto getControllerBinding(const std::shared_ptr& gamepad, Action action) -> SDL_GamepadButton; - - // --- Métodos de reseteo de estado de entrada --- - void resetInputStates(); + void saveGamepadConfigFromGamepad(std::shared_ptr gamepad); + void printConnectedGamepads() const; // --- Eventos --- auto handleEvent(const SDL_Event& event) -> std::string; - void printConnectedGamepads() const; - - auto findAvailableGamepadByName(const std::string& gamepad_name) -> std::shared_ptr; - void saveGamepadConfigFromGamepad(std::shared_ptr gamepad); - private: // --- Constantes --- - static constexpr Sint16 AXIS_THRESHOLD = 30000; - static constexpr Sint16 TRIGGER_THRESHOLD = 16384; // Umbral para triggers (aproximadamente 50% del rango) - static constexpr std::array BUTTON_INPUTS = {Action::JUMP}; // Listado de los inputs para jugar que utilizan botones, ni palancas ni crucetas + static constexpr Sint16 AXIS_THRESHOLD = 30000; // Umbral para ejes analógicos + static constexpr Sint16 TRIGGER_THRESHOLD = 16384; // Umbral para triggers (50% del rango) + static constexpr std::array BUTTON_INPUTS = {Action::JUMP}; // Inputs que usan botones - // --- Variables internas --- - Gamepads gamepads_; - Keyboard keyboard_; - std::string gamepad_mappings_file_; - std::string gamepad_configs_file_; - GamepadConfigs gamepad_configs_; + // --- Métodos --- + explicit Input(std::string game_controller_db_path, std::string gamepad_configs_file); + ~Input() = default; - // --- Métodos internos --- void initSDLGamePad(); static auto checkAxisInput(Action action, const std::shared_ptr& gamepad, bool repeat) -> bool; static auto checkTriggerInput(Action action, const std::shared_ptr& gamepad, bool repeat) -> bool; @@ -178,20 +133,19 @@ class Input { void addGamepadMappingsFromFile(); void discoverGamepads(); - // --- Métodos para integración con GamepadConfigManager --- void loadGamepadConfigs(); void saveGamepadConfigs(); void applyGamepadConfig(std::shared_ptr gamepad); - - // Métodos auxiliares opcionales void setGamepadConfigsFile(const std::string& filename); auto getGamepadConfig(const std::string& gamepad_name) -> GamepadConfig*; auto removeGamepadConfig(const std::string& gamepad_name) -> bool; - // --- Constructor y destructor --- - explicit Input(std::string game_controller_db_path, std::string gamepad_configs_file); - ~Input() = default; + // --- Variables miembro --- + static Input* instance; // Instancia única del singleton - // --- Singleton --- - static Input* instance; + Gamepads gamepads_{}; // Lista de gamepads conectados + Keyboard keyboard_{}; // Estado del teclado + std::string gamepad_mappings_file_{}; // Ruta al archivo de mappings + std::string gamepad_configs_file_{}; // Ruta al archivo de configuraciones + GamepadConfigs gamepad_configs_{}; // Configuraciones de gamepads guardadas }; \ No newline at end of file diff --git a/source/core/rendering/screen.cpp b/source/core/rendering/screen.cpp index 594e920..cee2705 100644 --- a/source/core/rendering/screen.cpp +++ b/source/core/rendering/screen.cpp @@ -39,9 +39,7 @@ auto Screen::get() -> Screen* { // Constructor Screen::Screen() - : window_width_(0), - window_height_(0), - palettes_(Resource::List::get()->getListByType(Resource::List::Type::PALETTE)) { + : palettes_(Resource::List::get()->getListByType(Resource::List::Type::PALETTE)) { // Arranca SDL VIDEO, crea la ventana y el renderizador initSDLVideo(); if (Options::video.fullscreen) { diff --git a/source/core/rendering/screen.hpp b/source/core/rendering/screen.hpp index 8f5c5d8..2efe1ec 100644 --- a/source/core/rendering/screen.hpp +++ b/source/core/rendering/screen.hpp @@ -14,125 +14,95 @@ namespace Rendering { class ShaderBackend; } -// Tipos de filtro -enum class ScreenFilter : Uint32 { - NEAREST = 0, - LINEAR = 1, -}; - class Screen { public: - // [SINGLETON] Crearemos el objeto con esta función estática - static void init(); + // Tipos de filtro + enum class Filter : Uint32 { + NEAREST = 0, + LINEAR = 1, + }; - // [SINGLETON] Destruiremos el objeto con esta función estática - static void destroy(); + // Singleton + static void init(); // Crea el singleton + static void destroy(); // Destruye el singleton + static auto get() -> Screen*; // Obtiene el singleton - // [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él - static auto get() -> Screen*; + // Renderizado + void clearRenderer(Color color = {0x00, 0x00, 0x00}); // Limpia el renderer + void clearSurface(Uint8 index); // Limpia la game_surface_ + void start(); // Prepara para empezar a dibujar en la textura de juego + void render(); // Vuelca el contenido del renderizador en pantalla + void update(float delta_time); // Actualiza la lógica de la clase - void clearRenderer(Color color = {0x00, 0x00, 0x00}); // Limpia el renderer - void clearSurface(Uint8 index); // Limpia la game_surface_ - void start(); // Prepara para empezar a dibujar en la textura de juego - void render(); // Vuelca el contenido del renderizador en pantalla - void update(float delta_time); // Actualiza la lógica de la clase - void setVideoMode(bool mode); // Establece el modo de video - void toggleVideoMode(); // Camibia entre pantalla completa y ventana - void toggleIntegerScale(); // Alterna entre activar y desactivar el escalado entero - void toggleVSync(); // Alterna entre activar y desactivar el V-Sync - auto decWindowZoom() -> bool; // Reduce el tamaño de la ventana - auto incWindowZoom() -> bool; // Aumenta el tamaño de la ventana - void setBorderColor(Uint8 color); // Cambia el color del borde - static void setBorderWidth(int width); // Establece el tamaño del borde - static void setBorderHeight(int height); // Establece el tamaño del borde - static void setBorderEnabled(bool value); // Establece si se ha de ver el borde en el modo ventana - void toggleBorder(); // Cambia entre borde visible y no visible - void toggleShaders(); // Cambia el estado de los shaders - void show(); // Muestra la ventana - void hide(); // Oculta la ventana + // Video y ventana + void setVideoMode(bool mode); // Establece el modo de video + void toggleVideoMode(); // Cambia entre pantalla completa y ventana + void toggleIntegerScale(); // Alterna entre activar y desactivar el escalado entero + void toggleVSync(); // Alterna entre activar y desactivar el V-Sync + auto decWindowZoom() -> bool; // Reduce el tamaño de la ventana + auto incWindowZoom() -> bool; // Aumenta el tamaño de la ventana + void show(); // Muestra la ventana + void hide(); // Oculta la ventana + + // Borde + void setBorderColor(Uint8 color); // Cambia el color del borde + static void setBorderWidth(int width); // Establece el ancho del borde + static void setBorderHeight(int height); // Establece el alto del borde + static void setBorderEnabled(bool value); // Establece si se ha de ver el borde + void toggleBorder(); // Cambia entre borde visible y no visible + + // Paletas y shaders + void nextPalette(); // Cambia a la siguiente paleta + void previousPalette(); // Cambia a la paleta anterior + void setPalete(); // Establece la paleta actual + void toggleShaders(); // Cambia el estado de los shaders + + // Surfaces y notificaciones void setRendererSurface(const std::shared_ptr& surface = nullptr); // Establece el renderizador para las surfaces - void nextPalette(); // Cambia la paleta - void previousPalette(); // Cambia la paleta - void setPalete(); // Establece la paleta - void setNotificationsEnabled(bool value); // Establece la visibilidad de las notificaciones - void toggleDebugInfo(); // Activa o desactiva la información de debug + void setNotificationsEnabled(bool value); // Establece la visibilidad de las notificaciones + void toggleDebugInfo(); // Activa o desactiva la información de debug - // --- Getters --- + // Getters auto getRenderer() -> SDL_Renderer*; auto getRendererSurface() -> std::shared_ptr; auto getBorderSurface() -> std::shared_ptr; [[nodiscard]] auto getText() const -> std::shared_ptr { return text_; } private: - // --- Constantes --- - static constexpr int WINDOWS_DECORATIONS = 35; // Decoraciones de la ventana - + // Estructuras struct DisplayMonitor { - std::string name; - int width; - int height; - int refresh_rate; + std::string name{}; + int width{0}; + int height{0}; + int refresh_rate{0}; }; struct FPS { - Uint32 ticks{0}; // Tiempo en milisegundos desde que se comenzó a contar. - int frame_count{0}; // Número acumulado de frames en el intervalo. - int last_value{0}; // Número de frames calculado en el último segundo. + Uint32 ticks{0}; // Tiempo en milisegundos desde que se comenzó a contar + int frame_count{0}; // Número acumulado de frames en el intervalo + int last_value{0}; // Número de frames calculado en el último segundo - // Constructor para inicializar la estructura. - FPS() = default; + void increment() { + frame_count++; + } - // Incrementador que se llama en cada frame. - void increment() { - frame_count++; - } - - // Método para calcular y devolver el valor de FPS. - auto calculate(Uint32 current_ticks) -> int { - if (current_ticks - ticks >= 1000) // Si ha pasado un segundo o más. - { - last_value = frame_count; // Actualizamos el valor del último FPS. - frame_count = 0; // Reiniciamos el contador de frames. - ticks = current_ticks; // Actualizamos el tiempo base. - } - return last_value; + auto calculate(Uint32 current_ticks) -> int { + if (current_ticks - ticks >= 1000) { + last_value = frame_count; + frame_count = 0; + ticks = current_ticks; } + return last_value; + } }; - // [SINGLETON] Objeto privado + // Constantes + static constexpr int WINDOWS_DECORATIONS = 35; // Decoraciones de la ventana + + // Singleton static Screen* screen; - // --- Objetos y punteros --- - SDL_Window* window_; // Ventana de la aplicación - SDL_Renderer* renderer_; // El renderizador de la ventana - SDL_Texture* game_texture_; // Textura donde se dibuja el juego - SDL_Texture* border_texture_; // Textura donde se dibuja el borde del juego - std::shared_ptr game_surface_; // Surface principal para manejar game_surface_data_ - std::shared_ptr border_surface_; // Surface para pintar el el borde de la pantalla - std::shared_ptr> renderer_surface_; // Puntero a la Surface que actua - std::unique_ptr shader_backend_; // Backend de shaders (OpenGL/Metal/Vulkan) - std::shared_ptr text_; // Objeto para escribir texto en pantalla de carga - - // --- Variables --- - int window_width_; // Ancho de la pantalla o ventana - int window_height_; // Alto de la pantalla o ventana - SDL_FRect game_surface_dstrect_; // Coordenadas donde se va a dibujar la textura del juego sobre la pantalla o ventana - Uint8 border_color_; // Color del borde añadido a la textura de juego para rellenar la pantalla - std::vector palettes_; // Listado de los ficheros de paletta disponibles - Uint8 current_palette_ = 0; // Indice para el vector de paletas - bool notifications_enabled_ = false; // indica si se muestran las notificaciones - FPS fps_; // Variable para gestionar los frames por segundo - std::string info_resolution_; // Texto con la informacion de la pantalla - std::string vertex_shader_source_; // Almacena el vertex shader - std::string fragment_shader_source_; // Almacena el fragment shader - DisplayMonitor display_monitor_; // Informacion de la pantalla - -#ifdef _DEBUG - bool show_debug_info_ = true; // Indica si ha de mostrar/ocultar la información de la pantalla -#else - bool show_debug_info_ = false; // Indica si ha de mostrar/ocultar la información de la pantalla -#endif - // --- Funciones --- + // Métodos privados void renderNotifications() const; // Dibuja las notificaciones void adjustWindowSize(); // Calcula el tamaño de la ventana void adjustRenderLogicalSize(); // Ajusta el tamaño lógico del renderizador @@ -148,9 +118,46 @@ class Screen { auto initSDLVideo() -> bool; // Arranca SDL VIDEO y crea la ventana void createText(); // Crea el objeto de texto - // Constructor + // Constructor y destructor Screen(); - - // Destructor ~Screen(); + + // Objetos SDL + SDL_Window* window_{nullptr}; // Ventana de la aplicación + SDL_Renderer* renderer_{nullptr}; // Renderizador de la ventana + SDL_Texture* game_texture_{nullptr}; // Textura donde se dibuja el juego + SDL_Texture* border_texture_{nullptr}; // Textura donde se dibuja el borde del juego + + // Surfaces y renderizado + std::shared_ptr game_surface_; // Surface principal del juego + std::shared_ptr border_surface_; // Surface para el borde de la pantalla + std::shared_ptr> renderer_surface_; // Puntero a la Surface activa + std::unique_ptr shader_backend_; // Backend de shaders (OpenGL/Metal/Vulkan) + std::shared_ptr text_; // Objeto para escribir texto + + // Configuración de ventana y pantalla + int window_width_{0}; // Ancho de la pantalla o ventana + int window_height_{0}; // Alto de la pantalla o ventana + SDL_FRect game_surface_dstrect_; // Coordenadas donde se dibuja la textura del juego + + // Paletas y colores + Uint8 border_color_{0}; // Color del borde + std::vector palettes_; // Listado de ficheros de paleta disponibles + Uint8 current_palette_{0}; // Índice para el vector de paletas + + // Estado y configuración + bool notifications_enabled_{false}; // Indica si se muestran las notificaciones + FPS fps_; // Gestor de frames por segundo + DisplayMonitor display_monitor_; // Información de la pantalla + + // Shaders + std::string info_resolution_; // Texto con la información de la pantalla + std::string vertex_shader_source_; // Almacena el vertex shader + std::string fragment_shader_source_; // Almacena el fragment shader + +#ifdef _DEBUG + bool show_debug_info_{true}; // Indica si ha de mostrar la información de debug +#else + bool show_debug_info_{false}; // Indica si ha de mostrar la información de debug +#endif }; \ No newline at end of file diff --git a/source/core/rendering/surface_animated_sprite.hpp b/source/core/rendering/surface_animated_sprite.hpp index 1c808b8..fc5da73 100644 --- a/source/core/rendering/surface_animated_sprite.hpp +++ b/source/core/rendering/surface_animated_sprite.hpp @@ -18,10 +18,6 @@ struct AnimationData { bool completed{false}; // Indica si ha finalizado la animación int current_frame{0}; // Frame actual float accumulated_time{0.0F}; // Tiempo acumulado para las animaciones (time-based) - - AnimationData() - - = default; }; using Animations = std::vector; @@ -43,12 +39,8 @@ class SurfaceAnimatedSprite : public SurfaceMovingSprite { public: // Constructor - // [DOC:29/10/2025] la surface ara se pillarà del .ANI. - // Necesite constructors que no requereixquen la surface al crear el objecte, - // ja que la trau al llegir el arxiu. Aixó afecta a totes les classes base... explicit SurfaceAnimatedSprite(const std::string& file_path); explicit SurfaceAnimatedSprite(const Animations& animations); - // [/DOC] SurfaceAnimatedSprite(std::shared_ptr surface, const std::string& file_path); SurfaceAnimatedSprite(std::shared_ptr surface, const Animations& animations); explicit SurfaceAnimatedSprite(std::shared_ptr surface) diff --git a/source/core/rendering/surface_sprite.cpp b/source/core/rendering/surface_sprite.cpp index e412662..52923e4 100644 --- a/source/core/rendering/surface_sprite.cpp +++ b/source/core/rendering/surface_sprite.cpp @@ -6,22 +6,20 @@ // Constructor SurfaceSprite::SurfaceSprite(std::shared_ptr surface, float x, float y, float w, float h) - : surface_(std::move(std::move(surface))), - pos_((SDL_FRect){x, y, w, h}), - clip_((SDL_FRect){0.0F, 0.0F, pos_.w, pos_.h}) {} + : surface_(std::move(surface)), + pos_{x, y, w, h}, + clip_{0.0F, 0.0F, pos_.w, pos_.h} {} SurfaceSprite::SurfaceSprite(std::shared_ptr surface, SDL_FRect rect) - : surface_(std::move(std::move(surface))), + : surface_(std::move(surface)), pos_(rect), - clip_((SDL_FRect){0, 0, pos_.w, pos_.h}) {} + clip_{0.0F, 0.0F, pos_.w, pos_.h} {} -SurfaceSprite::SurfaceSprite() - : pos_((SDL_FRect){0.0F, 0.0F, 0.0F, 0.0F}), - clip_(pos_) {} +SurfaceSprite::SurfaceSprite() = default; SurfaceSprite::SurfaceSprite(std::shared_ptr surface) - : surface_(std::move(std::move(surface))), - pos_((SDL_FRect){0.0F, 0.0F, surface_->getWidth(), surface_->getHeight()}), + : surface_(std::move(surface)), + pos_{0.0F, 0.0F, surface_->getWidth(), surface_->getHeight()}, clip_(pos_) {} // Muestra el sprite por pantalla @@ -47,8 +45,8 @@ void SurfaceSprite::setPosition(SDL_FPoint p) { // Reinicia las variables a cero void SurfaceSprite::clear() { - pos_ = {.x = 0, .y = 0, .w = 0, .h = 0}; - clip_ = {.x = 0, .y = 0, .w = 0, .h = 0}; + pos_ = {0.0F, 0.0F, 0.0F, 0.0F}; + clip_ = {0.0F, 0.0F, 0.0F, 0.0F}; } // Actualiza el estado del sprite (time-based) diff --git a/source/core/rendering/surface_sprite.hpp b/source/core/rendering/surface_sprite.hpp index bdc9717..eab485e 100644 --- a/source/core/rendering/surface_sprite.hpp +++ b/source/core/rendering/surface_sprite.hpp @@ -8,14 +8,8 @@ class Surface; // lines 5-5 // Clase SurfaceSprite class SurfaceSprite { - protected: - // Variables - std::shared_ptr surface_; // Surface donde estan todos los dibujos del sprite - SDL_FRect pos_; // Posición y tamaño donde dibujar el sprite - SDL_FRect clip_; // Rectangulo de origen de la surface que se dibujará en pantalla - public: - // Constructor + // Constructores SurfaceSprite(std::shared_ptr, float x, float y, float w, float h); SurfaceSprite(std::shared_ptr, SDL_FRect rect); SurfaceSprite(); @@ -24,51 +18,43 @@ class SurfaceSprite { // Destructor virtual ~SurfaceSprite() = default; - // Actualiza el estado del sprite (time-based) - virtual void update(float delta_time); + // Actualización y renderizado + virtual void update(float delta_time); // Actualiza el estado del sprite (time-based) + virtual void render(); // Muestra el sprite por pantalla + virtual void render(Uint8 source_color, Uint8 target_color); // Renderiza con reemplazo de color - // Muestra el sprite por pantalla - virtual void render(); - virtual void render(Uint8 source_color, Uint8 target_color); + // Gestión de estado + virtual void clear(); // Reinicia las variables a cero - // Reinicia las variables a cero - virtual void clear(); - - // Obtiene la posición y el tamaño + // Obtención de propiedades [[nodiscard]] auto getX() const -> float { return pos_.x; } [[nodiscard]] auto getY() const -> float { return pos_.y; } [[nodiscard]] auto getWidth() const -> float { return pos_.w; } [[nodiscard]] auto getHeight() const -> float { return pos_.h; } - - // Devuelve el rectangulo donde está el sprite [[nodiscard]] auto getPosition() const -> SDL_FRect { return pos_; } + [[nodiscard]] auto getClip() const -> SDL_FRect { return clip_; } + [[nodiscard]] auto getSurface() const -> std::shared_ptr { return surface_; } auto getRect() -> SDL_FRect& { return pos_; } - // Establece la posición y el tamaño + // Modificación de posición y tamaño void setX(float x) { pos_.x = x; } void setY(float y) { pos_.y = y; } void setWidth(float w) { pos_.w = w; } void setHeight(float h) { pos_.h = h; } - - // Establece la posición del objeto void setPosition(float x, float y); void setPosition(SDL_FPoint p); void setPosition(SDL_FRect r) { pos_ = r; } - - // Aumenta o disminuye la posición void incX(float value) { pos_.x += value; } void incY(float value) { pos_.y += value; } - // Obtiene el rectangulo que se dibuja de la surface - [[nodiscard]] auto getClip() const -> SDL_FRect { return clip_; } - - // Establece el rectangulo que se dibuja de la surface + // Modificación de clip y surface void setClip(SDL_FRect rect) { clip_ = rect; } - void setClip(float x, float y, float w, float h) { clip_ = (SDL_FRect){x, y, w, h}; } - - // Obtiene un puntero a la surface - [[nodiscard]] auto getSurface() const -> std::shared_ptr { return surface_; } - - // Establece la surface a utilizar + void setClip(float x, float y, float w, float h) { clip_ = SDL_FRect{x, y, w, h}; } void setSurface(std::shared_ptr surface) { surface_ = std::move(surface); } + + protected: + // Variables miembro + std::shared_ptr surface_{nullptr}; // Surface donde estan todos los dibujos del sprite + SDL_FRect pos_{0.0F, 0.0F, 0.0F, 0.0F}; // Posición y tamaño donde dibujar el sprite + SDL_FRect clip_{0.0F, 0.0F, 0.0F, 0.0F}; // Rectangulo de origen de la surface que se dibujará en pantalla }; \ No newline at end of file diff --git a/source/game/defaults.hpp b/source/game/defaults.hpp index 11942f6..651d458 100644 --- a/source/game/defaults.hpp +++ b/source/game/defaults.hpp @@ -2,12 +2,12 @@ #include -#include "core/rendering/screen.hpp" // Para ScreenFilter +#include "core/rendering/screen.hpp" // Para Screen::Filter #include "utils/utils.hpp" // Para PaletteColor // Forward declarations from Options namespace namespace Options { -//enum class ControlScheme; +// enum class ControlScheme; enum class NotificationPosition; } // namespace Options @@ -21,13 +21,13 @@ constexpr int GAME_HEIGHT = 192; // Alto de la ventana por defecto constexpr int WINDOW_ZOOM = 2; // Zoom de la ventana por defecto // VIDEO -constexpr bool VIDEO_MODE = false; // Modo de pantalla completa por defecto (false = ventana) -constexpr ScreenFilter VIDEO_FILTER = ScreenFilter::NEAREST; // Filtro por defecto -constexpr bool VIDEO_VERTICAL_SYNC = true; // Vsync activado por defecto -constexpr bool VIDEO_SHADERS = false; // Shaders desactivados por defecto -constexpr bool VIDEO_INTEGER_SCALE = true; // Escalado entero activado por defecto -constexpr bool VIDEO_KEEP_ASPECT = true; // Mantener aspecto activado por defecto -constexpr const char* PALETTE_NAME = "zx-spectrum"; // Paleta por defecto +constexpr bool VIDEO_MODE = false; // Modo de pantalla completa por defecto (false = ventana) +constexpr Screen::Filter VIDEO_FILTER = Screen::Filter::NEAREST; // Filtro por defecto +constexpr bool VIDEO_VERTICAL_SYNC = true; // Vsync activado por defecto +constexpr bool VIDEO_SHADERS = false; // Shaders desactivados por defecto +constexpr bool VIDEO_INTEGER_SCALE = true; // Escalado entero activado por defecto +constexpr bool VIDEO_KEEP_ASPECT = true; // Mantener aspecto activado por defecto +constexpr const char* PALETTE_NAME = "zx-spectrum"; // Paleta por defecto // BORDER constexpr bool BORDER_ENABLED = true; // Borde activado por defecto diff --git a/source/game/options.cpp b/source/game/options.cpp index 4794a2b..e5ecfbb 100644 --- a/source/game/options.cpp +++ b/source/game/options.cpp @@ -212,8 +212,8 @@ auto setOptions(const std::string& var, const std::string& value) -> bool { {"video.mode", [](const std::string& v) { video.fullscreen = stringToBool(v); }}, {"video.filter", [](const std::string& v) { int val = safeStoi(v, static_cast(GameDefaults::VIDEO_FILTER)); - if (val == static_cast(ScreenFilter::NEAREST) || val == static_cast(ScreenFilter::LINEAR)) { - video.filter = static_cast(val); + if (val == static_cast(Screen::Filter::NEAREST) || val == static_cast(Screen::Filter::LINEAR)) { + video.filter = static_cast(val); } else { video.filter = GameDefaults::VIDEO_FILTER; } diff --git a/source/game/options.hpp b/source/game/options.hpp index 57295a1..2419989 100644 --- a/source/game/options.hpp +++ b/source/game/options.hpp @@ -6,7 +6,7 @@ #include // Para string, basic_string #include -#include "core/rendering/screen.hpp" // Para ScreenFilter +#include "core/rendering/screen.hpp" // Para Screen::Filter #include "utils/defines.hpp" // Para WINDOW_CAPTION #include "utils/utils.hpp" // Para Color, Palette @@ -161,7 +161,7 @@ struct Border { // Estructura para las opciones de video struct Video { bool fullscreen{GameDefaults::VIDEO_MODE}; // Contiene el valor del modo de pantalla completa - ScreenFilter filter{GameDefaults::VIDEO_FILTER}; // Filtro usado para el escalado de la imagen + Screen::Filter filter{GameDefaults::VIDEO_FILTER}; // Filtro usado para el escalado de la imagen bool vertical_sync{GameDefaults::VIDEO_VERTICAL_SYNC}; // Indica si se quiere usar vsync o no bool shaders{GameDefaults::VIDEO_SHADERS}; // Indica si se van a usar shaders o no bool integer_scale{GameDefaults::VIDEO_INTEGER_SCALE}; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa @@ -174,7 +174,7 @@ struct Video { Video() = default; // Constructor - Video(bool is_fullscreen, ScreenFilter screen_filter, bool vsync, bool use_shaders, bool int_scale, bool keep_aspect_ratio, Border video_border, std::string palette_name) + Video(bool is_fullscreen, Screen::Filter screen_filter, bool vsync, bool use_shaders, bool int_scale, bool keep_aspect_ratio, Border video_border, std::string palette_name) : fullscreen(is_fullscreen), filter(screen_filter), vertical_sync(vsync), @@ -246,17 +246,17 @@ struct Game { }; // --- Variables globales (inline C++17+) --- -inline std::string version{}; // Versión del fichero de configuración. Sirve para saber si las opciones son compatibles -inline bool console{false}; // Indica si ha de mostrar información por la consola de texto -inline Cheat cheats{}; // Contiene trucos y ventajas para el juego -inline Game game{}; // Opciones de juego -inline Video video{}; // Opciones de video -inline Stats stats{}; // Datos con las estadisticas de juego -inline Notification notifications{}; // Opciones relativas a las notificaciones; -inline Window window{}; // Opciones relativas a la ventana -inline Audio audio{}; // Opciones relativas al audio -inline ControlScheme controls{}; // Teclas usadas para jugar -inline GamepadControlScheme gamepad_controls{}; // Botones del gamepad usados para jugar +inline std::string version{}; // Versión del fichero de configuración. Sirve para saber si las opciones son compatibles +inline bool console{false}; // Indica si ha de mostrar información por la consola de texto +inline Cheat cheats{}; // Contiene trucos y ventajas para el juego +inline Game game{}; // Opciones de juego +inline Video video{}; // Opciones de video +inline Stats stats{}; // Datos con las estadisticas de juego +inline Notification notifications{}; // Opciones relativas a las notificaciones; +inline Window window{}; // Opciones relativas a la ventana +inline Audio audio{}; // Opciones relativas al audio +inline ControlScheme controls{}; // Teclas usadas para jugar +inline GamepadControlScheme gamepad_controls{}; // Botones del gamepad usados para jugar // --- Funciones --- void init(); // Crea e inicializa las opciones del programa