refactor(#28): Director rep EngineConfig + ConfigPersistence, main orquestra

Pas 5/N del hallazgo #28.

Director deixa d'incloure game/options.hpp i les seves crides a
Options::*. El seu ctor accepta ara:
- Config::EngineConfig& cfg     → la struct runtime (window, console, ...).
- Config::ConfigPersistence     → 4 lambdes (init/set_path/load/save)
  que delegen la persistència a la capa concreta (game/Options::*).

Cap més referència a Options:: ni a "game/..." dins del Director:
- cfg_->* substitueix tot Options::* (window, console, player1/2,
  rendering, engine_config).
- persistence_.{init,save,load,set_path} substitueix les funcions
  d'I/O de YAML.

run() i checkProgramArguments deixen de ser estàtics (necessiten
accés a cfg_ i persistence_). Això també desfà el smell del
hallazgo #37 (Director::run estàtic que llegia estat d'instància).

main.cpp queda com a orquestrador: construeix la struct
ConfigPersistence amb lambdes que enllacen amb Options::* i la
injecta al Director.

Afegit: Config::ConfigPersistence a engine_config.hpp.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-20 19:40:52 +02:00
parent fdd34eb943
commit 41ce3fece5
4 changed files with 89 additions and 55 deletions
+26 -24
View File
@@ -19,7 +19,6 @@
#include "core/resources/resource_loader.hpp"
#include "core/utils/path_utils.hpp"
#include "debug_overlay.hpp"
#include "game/options.hpp"
#include "game/scenes/game_scene.hpp"
#include "game/scenes/logo_scene.hpp"
#include "game/scenes/title_scene.hpp"
@@ -38,11 +37,15 @@ using SceneManager::SceneContext;
using SceneType = SceneContext::SceneType;
// Constructor
Director::Director(std::vector<std::string> const& args) {
Director::Director(std::vector<std::string> const& args,
Config::EngineConfig& cfg,
Config::ConfigPersistence persistence)
: cfg_(&cfg),
persistence_(std::move(persistence)) {
std::cout << "Orni Attack - Inici\n";
// Inicialitzar opciones con valors per defecte
Options::init();
persistence_.init_defaults();
// Comprovar arguments del programa
executable_path_ = checkProgramArguments(args);
@@ -90,22 +93,22 @@ Director::Director(std::vector<std::string> const& args) {
createSystemFolder(std::string("jailgames/") + Project::NAME);
// Establir ruta del file de configuración
Options::setConfigFile(system_folder_ + "/config.yaml");
persistence_.set_path(system_folder_ + "/config.yaml");
// Carregar o crear configuración
Options::loadFromFile();
persistence_.load();
// Inicialitzar sistema de input
Input::init("data/gamecontrollerdb.txt");
// Aplicar configuración de controls dels jugadors
Input::get()->applyPlayer1Bindings(Options::player1);
Input::get()->applyPlayer2Bindings(Options::player2);
Input::get()->applyPlayer1Bindings(cfg_->player1);
Input::get()->applyPlayer2Bindings(cfg_->player2);
if (Options::console) {
if (cfg_->console) {
std::cout << "Configuración carregada\n";
std::cout << " Finestra: " << Options::window.width << "×"
<< Options::window.height << '\n';
std::cout << " Finestra: " << cfg_->window.width << "×"
<< cfg_->window.height << '\n';
std::cout << " Input: " << Input::get()->getNumGamepads()
<< " gamepad(s) detectat(s)\n";
}
@@ -115,7 +118,7 @@ Director::Director(std::vector<std::string> const& args) {
Director::~Director() {
// Guardar opciones
Options::saveToFile();
persistence_.save();
// Cleanup input
Input::destroy();
@@ -136,11 +139,11 @@ auto Director::checkProgramArguments(std::vector<std::string> const& args)
const std::string& argument = args[i];
if (argument == "--console") {
Options::console = true;
cfg_->console = true;
std::cout << "Mode consola activat\n";
} else if (argument == "--reset-config") {
Options::init();
Options::saveToFile();
persistence_.init_defaults();
persistence_.save();
std::cout << "Configuración restablida als valors per defecte\n";
}
}
@@ -207,7 +210,7 @@ void Director::createSystemFolder(const std::string& folder) {
}
}
if (Options::console) {
if (cfg_->console) {
std::cout << "Carpeta del sistema: " << system_folder_ << '\n';
}
}
@@ -216,18 +219,17 @@ void Director::createSystemFolder(const std::string& folder) {
auto Director::run() -> int {
// Calculate initial size from saved zoom_factor
int initial_width = static_cast<int>(std::round(
Defaults::Window::WIDTH * Options::window.zoom_factor));
Defaults::Window::WIDTH * cfg_->window.zoom_factor));
int initial_height = static_cast<int>(std::round(
Defaults::Window::HEIGHT * Options::window.zoom_factor));
Defaults::Window::HEIGHT * cfg_->window.zoom_factor));
// Crear gestor SDL con configuración de Options.
// Inyectamos la engine_config + un callback per persistir-la quan
// toggleVSync (F4) muti vsync, sense que sdl_manager conegui Options.
SDLManager sdl(initial_width, initial_height, Options::window.fullscreen, Options::engine_config, [] { Options::saveToFile(); });
// Crear gestor SDL amb la engine_config + callback de persistència
// per a quan toggleVSync (F4) muti vsync. Mantenim sdl_manager agnòstic.
SDLManager sdl(initial_width, initial_height, cfg_->window.fullscreen, *cfg_, [this] { persistence_.save(); });
// CRÍTIC: Forçar ocultació del cursor DESPRÉS de toda la inicialización SDL
// Això evita que SDL mostre el cursor automàticament durante la creació de la finestra
if (!Options::window.fullscreen) {
if (!cfg_->window.fullscreen) {
Mouse::forceHide();
}
@@ -246,7 +248,7 @@ auto Director::run() -> int {
// Precachear música para evitar lag al empezar
AudioResource::getMusic("title.ogg");
AudioResource::getMusic("game.ogg");
if (Options::console) {
if (cfg_->console) {
std::cout << "Música precacheada\n";
}
@@ -260,7 +262,7 @@ auto Director::run() -> int {
// Overlay de debug (FPS + VSync). Vive en el Director porque es global
// a todas las escenas. Toggle con F11 (visible por defecto en _DEBUG).
System::DebugOverlay debug_overlay(sdl.getRenderer(), Options::rendering);
System::DebugOverlay debug_overlay(sdl.getRenderer(), cfg_->rendering);
// Bucle principal: construir escena → frame loop → destruir → siguiente.
while (context.nextScene() != SceneType::EXIT) {