From dfbd8a430b993e570d7545a3d7f42d332bc89955 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Wed, 11 Mar 2026 22:44:17 +0100 Subject: [PATCH] afegit escenari personalitzat per parametre --- source/defines.hpp | 1 + source/engine.cpp | 53 +++++++++++++++++++++++++++++++--- source/engine.hpp | 11 +++++++ source/input/input_handler.cpp | 7 +++++ source/main.cpp | 17 +++++++++++ source/scene/scene_manager.cpp | 5 +++- source/scene/scene_manager.hpp | 9 +++++- source/ui/ui_manager.cpp | 2 ++ 8 files changed, 99 insertions(+), 6 deletions(-) diff --git a/source/defines.hpp b/source/defines.hpp index 7e0bac1..e03c0e8 100644 --- a/source/defines.hpp +++ b/source/defines.hpp @@ -59,6 +59,7 @@ constexpr int BALL_COUNT_SCENARIOS[8] = {10, 50, 100, 500, 1000, 5000, 10000, 50 constexpr int DEMO_AUTO_MIN_SCENARIO = 2; // mínimo 100 bolas constexpr int DEMO_AUTO_MAX_SCENARIO = 7; // máximo sin restricción hardware (ajustado por benchmark) constexpr int LOGO_MIN_SCENARIO_IDX = 4; // mínimo 1000 bolas (sustituye LOGO_MODE_MIN_BALLS) +constexpr int CUSTOM_SCENARIO_IDX = 8; // Escenario custom opcional (tecla 9, --custom-balls) // Estructura para representar colores RGB struct Color { diff --git a/source/engine.cpp b/source/engine.cpp index 9cb2fe9..7fa8c4e 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -226,6 +226,10 @@ bool Engine::initialize(int width, int height, int zoom, bool fullscreen, AppMod scene_manager_ = std::make_unique(current_screen_width_, current_screen_height_); scene_manager_->initialize(0, texture_, theme_manager_.get()); // Escenario 0 (10 bolas) por defecto + // Propagar configuración custom si fue establecida antes de initialize() + if (custom_scenario_enabled_) + scene_manager_->setCustomBallCount(custom_scenario_balls_); + // Calcular tamaño físico de ventana ANTES de inicializar UIManager // NOTA: No llamar a updatePhysicalWindowSize() aquí porque ui_manager_ aún no existe // Calcular manualmente para poder pasar valores al constructor de UIManager @@ -550,6 +554,15 @@ void Engine::switchTexture() { switchTextureInternal(true); // Mostrar notificación en modo manual } +// Escenario custom (--custom-balls) +void Engine::setCustomScenario(int balls) { + custom_scenario_balls_ = balls; + custom_scenario_enabled_ = true; + // scene_manager_ puede no existir aún (llamada pre-init); propagación en initialize() + if (scene_manager_) + scene_manager_->setCustomBallCount(balls); +} + // Escenarios (número de pelotas) void Engine::changeScenario(int scenario_id, const char* notification_text) { // Pasar el modo actual al SceneManager para inicialización correcta @@ -1420,8 +1433,12 @@ void Engine::executeDemoAction(bool is_lite) { accumulated_weight += DEMO_WEIGHT_SCENARIO; if (random_value < accumulated_weight) { int auto_max = std::min(max_auto_scenario_, DEMO_AUTO_MAX_SCENARIO); - int range = auto_max - DEMO_AUTO_MIN_SCENARIO + 1; - int new_scenario = DEMO_AUTO_MIN_SCENARIO + (rand() % range); + std::vector candidates; + for (int i = DEMO_AUTO_MIN_SCENARIO; i <= auto_max; ++i) + candidates.push_back(i); + if (custom_scenario_enabled_ && custom_auto_available_) + candidates.push_back(CUSTOM_SCENARIO_IDX); + int new_scenario = candidates[rand() % candidates.size()]; scene_manager_->changeScenario(new_scenario, current_mode_); // Si estamos en modo SHAPE, regenerar la figura con nuevo número de pelotas @@ -1578,8 +1595,12 @@ void Engine::executeRandomizeOnDemoStart(bool is_lite) { // 2. Escenario - rango dinámico según benchmark de rendimiento int auto_max = std::min(max_auto_scenario_, DEMO_AUTO_MAX_SCENARIO); - int range = auto_max - DEMO_AUTO_MIN_SCENARIO + 1; - int new_scenario = DEMO_AUTO_MIN_SCENARIO + (rand() % range); + std::vector candidates; + for (int i = DEMO_AUTO_MIN_SCENARIO; i <= auto_max; ++i) + candidates.push_back(i); + if (custom_scenario_enabled_ && custom_auto_available_) + candidates.push_back(CUSTOM_SCENARIO_IDX); + int new_scenario = candidates[rand() % candidates.size()]; scene_manager_->changeScenario(new_scenario, current_mode_); // Si estamos en modo SHAPE, generar la figura y activar atracción @@ -1653,6 +1674,30 @@ void Engine::runPerformanceBenchmark() { last_frame_time_ = 0; }; + // Test escenario custom (independiente de max_auto_scenario_) + custom_auto_available_ = false; + if (custom_scenario_enabled_) { + scene_manager_->changeScenario(CUSTOM_SCENARIO_IDX, current_mode_); + last_frame_time_ = 0; + for (int w = 0; w < WARMUP_FRAMES; ++w) { + calculateDeltaTime(); + SDL_Event e; while (SDL_PollEvent(&e)) {} + update(); + render(); + } + int frame_count = 0; + Uint64 start = SDL_GetTicks(); + while (SDL_GetTicks() - start < static_cast(BENCH_DURATION_MS)) { + calculateDeltaTime(); + SDL_Event e; while (SDL_PollEvent(&e)) {} + update(); + render(); + ++frame_count; + } + float fps = static_cast(frame_count) / (BENCH_DURATION_MS / 1000.0f); + custom_auto_available_ = (fps >= monitor_hz); + } + // Probar de más pesado a más ligero for (int idx = DEMO_AUTO_MAX_SCENARIO; idx >= DEMO_AUTO_MIN_SCENARIO; --idx) { scene_manager_->changeScenario(idx, current_mode_); diff --git a/source/engine.hpp b/source/engine.hpp index 1240457..1f8a81d 100644 --- a/source/engine.hpp +++ b/source/engine.hpp @@ -75,6 +75,12 @@ class Engine { void setKioskMode(bool enabled) { kiosk_mode_ = enabled; } bool isKioskMode() const { return kiosk_mode_; } + // Escenario custom (tecla 9, --custom-balls) + void setCustomScenario(int balls); + bool isCustomScenarioEnabled() const { return custom_scenario_enabled_; } + bool isCustomAutoAvailable() const { return custom_auto_available_; } + int getCustomScenarioBalls() const { return custom_scenario_balls_; } + // Notificaciones (público para InputHandler) void showNotificationForAction(const std::string& text); @@ -175,6 +181,11 @@ class Engine { float demo_next_action_time_ = 0.0f; // Tiempo aleatorio hasta próxima acción (segundos) int max_auto_scenario_ = 5; // Índice máximo en modos auto (default conservador: 5000 bolas) + // Escenario custom (--custom-balls) + int custom_scenario_balls_ = 0; + bool custom_scenario_enabled_ = false; + bool custom_auto_available_ = false; + // Sistema de convergencia para LOGO MODE (escala con resolución) // Usado por performLogoAction() para detectar cuando las bolas forman el logo float shape_convergence_ = 0.0f; // % de pelotas cerca del objetivo (0.0-1.0) diff --git a/source/input/input_handler.cpp b/source/input/input_handler.cpp index 6006841..1b02b15 100644 --- a/source/input/input_handler.cpp +++ b/source/input/input_handler.cpp @@ -224,6 +224,13 @@ bool InputHandler::processEvents(Engine& engine) { engine.changeScenario(7, "50,000 Pelotas"); break; + case SDLK_9: + if (engine.isCustomScenarioEnabled()) { + std::string custom_notif = std::to_string(engine.getCustomScenarioBalls()) + " Pelotas"; + engine.changeScenario(CUSTOM_SCENARIO_IDX, custom_notif.c_str()); + } + break; + // Controles de zoom dinámico (solo si no estamos en fullscreen) case SDLK_F1: if (engine.isKioskMode()) engine.showNotificationForAction(KIOSK_NOTIFICATION_TEXT); diff --git a/source/main.cpp b/source/main.cpp index 87f27b7..e9e1a73 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -18,6 +18,7 @@ void printHelp() { std::cout << " -F, --real-fullscreen Modo pantalla completa real (F4 - nativo)\n"; std::cout << " -k, --kiosk Modo kiosko (F4 fijo, sin ESC, sin zoom)\n"; std::cout << " -m, --mode Modo inicial: sandbox, demo, demo-lite, logo (default: sandbox)\n"; + std::cout << " --custom-balls Activa escenario custom (tecla 9) con N pelotas\n"; std::cout << " --help Mostrar esta ayuda\n\n"; std::cout << "Ejemplos:\n"; std::cout << " vibe3_physics # 320x240 zoom 3 (ventana 960x720)\n"; @@ -36,6 +37,7 @@ int main(int argc, char* argv[]) { int width = 0; int height = 0; int zoom = 0; + int custom_balls = 0; bool fullscreen = false; bool real_fullscreen = false; bool kiosk_mode = false; @@ -104,6 +106,18 @@ int main(int argc, char* argv[]) { std::cerr << "Error: -m/--mode requiere un valor\n"; return -1; } + } else if (strcmp(argv[i], "--custom-balls") == 0) { + if (i + 1 < argc) { + int n = atoi(argv[++i]); + if (n < 1) { + std::cerr << "Error: --custom-balls requiere un valor >= 1\n"; + return -1; + } + custom_balls = n; + } else { + std::cerr << "Error: --custom-balls requiere un valor\n"; + return -1; + } } else { std::cerr << "Error: Opción desconocida '" << argv[i] << "'\n"; printHelp(); @@ -118,6 +132,9 @@ int main(int argc, char* argv[]) { Engine engine; + if (custom_balls > 0) + engine.setCustomScenario(custom_balls); // pre-init: asigna campos antes del benchmark + if (!engine.initialize(width, height, zoom, fullscreen, initial_mode)) { std::cout << "¡Error al inicializar el engine!" << std::endl; return -1; diff --git a/source/scene/scene_manager.cpp b/source/scene/scene_manager.cpp index e1f1ecd..e579aad 100644 --- a/source/scene/scene_manager.cpp +++ b/source/scene/scene_manager.cpp @@ -44,7 +44,10 @@ void SceneManager::changeScenario(int scenario_id, SimulationMode mode) { changeGravityDirection(GravityDirection::DOWN); // Crear las bolas según el escenario - for (int i = 0; i < BALL_COUNT_SCENARIOS[scenario_id]; ++i) { + int ball_count = (scenario_id == CUSTOM_SCENARIO_IDX) + ? custom_ball_count_ + : BALL_COUNT_SCENARIOS[scenario_id]; + for (int i = 0; i < ball_count; ++i) { float X, Y, VX, VY; // Inicialización según SimulationMode (RULES.md líneas 23-26) diff --git a/source/scene/scene_manager.hpp b/source/scene/scene_manager.hpp index c0da7be..d43ea0b 100644 --- a/source/scene/scene_manager.hpp +++ b/source/scene/scene_manager.hpp @@ -50,11 +50,17 @@ class SceneManager { /** * @brief Cambia el número de bolas según escenario - * @param scenario_id Índice del escenario (0-7 para 10 a 50,000 bolas) + * @param scenario_id Índice del escenario (0-7 para 10 a 50,000 bolas; 8 = custom) * @param mode Modo de simulación actual (afecta inicialización) */ void changeScenario(int scenario_id, SimulationMode mode); + /** + * @brief Configura el número de bolas para el escenario custom (índice 8) + * @param n Número de bolas del escenario custom + */ + void setCustomBallCount(int n) { custom_ball_count_ = n; } + /** * @brief Actualiza textura y tamaño de todas las bolas * @param new_texture Nueva textura compartida @@ -146,6 +152,7 @@ class SceneManager { std::vector> balls_; GravityDirection current_gravity_; int scenario_; + int custom_ball_count_ = 0; // Número de bolas para escenario custom (índice 8) // === Configuración de pantalla === int screen_width_; diff --git a/source/ui/ui_manager.cpp b/source/ui/ui_manager.cpp index c9a1b28..3668754 100644 --- a/source/ui/ui_manager.cpp +++ b/source/ui/ui_manager.cpp @@ -279,6 +279,8 @@ void UIManager::renderDebugHUD(const Engine* engine, // Máximo de pelotas en modos automáticos (resultado del benchmark) int max_auto_idx = engine->getMaxAutoScenario(); int max_auto_balls = BALL_COUNT_SCENARIOS[max_auto_idx]; + if (engine->isCustomAutoAvailable() && engine->getCustomScenarioBalls() > max_auto_balls) + max_auto_balls = engine->getCustomScenarioBalls(); std::string max_auto_text; if (max_auto_balls >= 1000) { std::string count_str = std::to_string(max_auto_balls);