From f7770174607b4f3152a09ca5a4cef9b469d27c12 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Wed, 20 May 2026 18:27:38 +0200 Subject: [PATCH] refactor: esborrar Defaults::Physics::{ENEMY,BULLET}_SPEED i VELOCITY_SCALE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Constants legacy heretades del Pascal, en unitats/frame, que la migració a SDL3 va deixar sense ús real: - ENEMY_SPEED i BULLET_SPEED només es llegien des d'Options::physics (esborrat al #21) i des de Constants::VELOCITAT/VELOCITAT_MAX (esborrat al #24). Ara amb zero callers. - VELOCITY_SCALE no tenia callers (les velocitats efectives es calculen a Bullet::BULLET_SPEED = 140 px/s i a Defaults::Enemies::{Pentagon,Cuadrado,Molinillo}::VELOCITAT). S'ajusta el comentari del namespace per reflectir que ara conté només la física del control de la nau. Hallazgo #25 de CODE_REVIEW.md. Co-Authored-By: Claude Opus 4.7 (1M context) --- source/core/defaults.hpp | 1039 +++++++++++++++++++------------------- 1 file changed, 518 insertions(+), 521 deletions(-) diff --git a/source/core/defaults.hpp b/source/core/defaults.hpp index 1a2be14..9678341 100644 --- a/source/core/defaults.hpp +++ b/source/core/defaults.hpp @@ -5,526 +5,523 @@ #include namespace Defaults { -// Configuración de ventana -namespace Window { -constexpr int WIDTH = 1280; -constexpr int HEIGHT = 720; -constexpr int MIN_WIDTH = 640; // Mínimo: mitad del baseline (16:9) -constexpr int MIN_HEIGHT = 360; -// Zoom system -constexpr float BASE_ZOOM = 1.0F; // 1280x720 baseline (16:9) -constexpr float MIN_ZOOM = 0.5F; // 640x360 minimum -constexpr float ZOOM_INCREMENT = 0.1F; // 10% steps (F1/F2) -constexpr bool FULLSCREEN = true; // Pantalla completa activada por defecto -} // namespace Window - -// Dimensiones base del juego (coordenadas lógicas, 16:9) -namespace Game { -constexpr int WIDTH = 1280; -constexpr int HEIGHT = 720; -} // namespace Game - -// Zones del juego (SDL_FRect con cálculos automáticos basat en porcentajes) -namespace Zones { -// --- CONFIGURACIÓ DE PORCENTATGES --- -// Todas las zones definides como a porcentajes de Game::WIDTH (640) i Game::HEIGHT (480) - -// Percentatges de height (divisió vertical) -constexpr float SCOREBOARD_TOP_HEIGHT_PERCENT = 0.02F; // 10% superior -constexpr float MAIN_PLAYAREA_HEIGHT_PERCENT = 0.88F; // 80% central -constexpr float SCOREBOARD_BOTTOM_HEIGHT_PERCENT = 0.10F; // 10% inferior - -// Padding horizontal para PLAYAREA (dentro de MAIN_PLAYAREA) -constexpr float PLAYAREA_PADDING_HORIZONTAL_PERCENT = 0.015F; // 5% a cada costat - -// --- CÀLCULS AUTOMÀTICS DE PÍXELS --- -// Cálculos automáticos a partir dels porcentajes - -// Alçades -constexpr float SCOREBOARD_TOP_H = Game::HEIGHT * SCOREBOARD_TOP_HEIGHT_PERCENT; -constexpr float MAIN_PLAYAREA_H = Game::HEIGHT * MAIN_PLAYAREA_HEIGHT_PERCENT; -constexpr float SCOREBOARD_BOTTOM_H = Game::HEIGHT * SCOREBOARD_BOTTOM_HEIGHT_PERCENT; - -// Posicions Y -constexpr float SCOREBOARD_TOP_Y = 0.0F; -constexpr float MAIN_PLAYAREA_Y = SCOREBOARD_TOP_H; -constexpr float SCOREBOARD_BOTTOM_Y = MAIN_PLAYAREA_Y + MAIN_PLAYAREA_H; - -// Padding horizontal de PLAYAREA -constexpr float PLAYAREA_PADDING_H = Game::WIDTH * PLAYAREA_PADDING_HORIZONTAL_PERCENT; - -// --- ZONES FINALS (SDL_FRect) --- - -// Marcador superior (reservado para futuro uso) -// Ocupa el 2% superior -constexpr SDL_FRect SCOREBOARD_TOP = { - 0.0F, // x = 0.0 - SCOREBOARD_TOP_Y, // y = 0.0 - static_cast(Game::WIDTH), // ancho completo - SCOREBOARD_TOP_H // alto -}; - -// Área de juego principal (contenedor del 80% central, sin padding) -// Ocupa el 88% central, ancho completo -constexpr SDL_FRect MAIN_PLAYAREA = { - 0.0F, // x = 0.0 - MAIN_PLAYAREA_Y, // debajo del scoreboard superior - static_cast(Game::WIDTH), // ancho completo - MAIN_PLAYAREA_H // alto -}; - -// Zona de juego real (con padding horizontal del 5%) -// Ocupa: dentro de MAIN_PLAYAREA, con márgenes laterales -// Se utiliza para límites del juego, colisiones, spawn -constexpr SDL_FRect PLAYAREA = { - PLAYAREA_PADDING_H, // padding horizontal - MAIN_PLAYAREA_Y, // debajo del scoreboard superior (igual que MAIN_PLAYAREA) - Game::WIDTH - (2.0F * PLAYAREA_PADDING_H), // ancho con padding - MAIN_PLAYAREA_H // alto (igual que MAIN_PLAYAREA) -}; - -// Marcador inferior (marcador actual) -// Ocupa el 10% inferior -constexpr SDL_FRect SCOREBOARD = { - 0.0F, // x = 0.0 - SCOREBOARD_BOTTOM_Y, // fondo - static_cast(Game::WIDTH), // ancho completo - SCOREBOARD_BOTTOM_H // alto -}; - -// Padding horizontal del marcador (para alinear zonas izquierda/derecha con PLAYAREA) -constexpr float SCOREBOARD_PADDING_H = 0.0F; // Game::WIDTH * 0.015f; -} // namespace Zones - -// Objetos del juego -namespace Entities { -constexpr int MAX_ORNIS = 15; -constexpr int MAX_BALES = 3; - -constexpr float SHIP_RADIUS = 12.0F; -constexpr float ENEMY_RADIUS = 20.0F; -constexpr float BULLET_RADIUS = 3.0F; -} // namespace Entities - -// Paleta semántica por tipo de entidad. Si una entity declara color, lo -// pasa al pipeline con alpha=255 (sentinela "color válido"); si no, se -// usa el color global del oscilador (g_current_line_color). -namespace Palette { -constexpr SDL_Color SHIP = {.r = 255, .g = 255, .b = 255, .a = 255}; // Blanco neutro -constexpr SDL_Color BULLET = {.r = 120, .g = 255, .b = 140, .a = 255}; // Verde laser -constexpr SDL_Color PENTAGON = {.r = 120, .g = 170, .b = 255, .a = 255}; // Azul "esquivador" -constexpr SDL_Color QUADRAT = {.r = 255, .g = 110, .b = 110, .a = 255}; // Rojo "tank" -constexpr SDL_Color MOLINILLO = {.r = 255, .g = 130, .b = 255, .a = 255}; // Magenta agresivo -} // namespace Palette - -// Ship (nave del player) -namespace Ship { -// Invulnerabilidad post-respawn -constexpr float INVULNERABILITY_DURATION = 3.0F; // Segundos de invulnerabilidad - -// Parpadeo visual durante invulnerabilidad -constexpr float BLINK_VISIBLE_TIME = 0.1F; // Tiempo visible (segundos) -constexpr float BLINK_INVISIBLE_TIME = 0.1F; // Tiempo invisible (segundos) -// Frecuencia total: 0.2s/ciclo = 5 Hz (~15 parpadeos en 3s) -} // namespace Ship - -// Game rules (lives, respawn, game over) -namespace Game { -constexpr int STARTING_LIVES = 3; // Initial lives -constexpr float DEATH_DURATION = 3.0F; // Seconds of death animation -constexpr float GAME_OVER_DURATION = 5.0F; // Seconds to display game over -constexpr float COLLISION_SHIP_ENEMY_AMPLIFIER = 0.80F; // 80% hitbox (generous) -constexpr float COLLISION_BULLET_ENEMY_AMPLIFIER = 1.15F; // 115% hitbox (generous) - -// Friendly fire system -constexpr bool FRIENDLY_FIRE_ENABLED = true; // Activar friendly fire -constexpr float COLLISION_BULLET_PLAYER_AMPLIFIER = 1.0F; // Hitbox exacto (100%) -constexpr float BULLET_GRACE_PERIOD = 0.2F; // Inmunidad post-disparo (s) - -// Transición LEVEL_START (mensajes aleatorios PRE-level) -constexpr float LEVEL_START_DURATION = 3.0F; // Duración total -constexpr float LEVEL_START_TYPING_RATIO = 0.3F; // 30% escribiendo, 70% mostrando - -// Transición LEVEL_COMPLETED (mensaje "GOOD JOB COMMANDER!") -constexpr float LEVEL_COMPLETED_DURATION = 3.0F; // Duración total -constexpr float LEVEL_COMPLETED_TYPING_RATIO = 0.0F; // 0.0 = sin typewriter (directo) - -// Transición INIT_HUD (animación inicial del HUD) -constexpr float INIT_HUD_DURATION = 3.0F; // Duración total del estado - -// Ratios de animación (inicio y fin como porcentajes del tiempo total) -// RECT (rectángulo de márgenes) -constexpr float INIT_HUD_RECT_RATIO_INIT = 0.30F; -constexpr float INIT_HUD_RECT_RATIO_END = 0.85F; - -// SCORE (marcador de puntuación) -constexpr float INIT_HUD_SCORE_RATIO_INIT = 0.60F; -constexpr float INIT_HUD_SCORE_RATIO_END = 0.90F; - -// SHIP1 (nave player 1) -constexpr float INIT_HUD_SHIP1_RATIO_INIT = 0.0F; -constexpr float INIT_HUD_SHIP1_RATIO_END = 1.0F; - -// SHIP2 (nave player 2) -constexpr float INIT_HUD_SHIP2_RATIO_INIT = 0.20F; -constexpr float INIT_HUD_SHIP2_RATIO_END = 1.0F; - -// Posición inicial de la nave en INIT_HUD (75% de altura de zona de juego) -constexpr float INIT_HUD_SHIP_START_Y_RATIO = 0.75F; // 75% desde el top de PLAYAREA - -// Spawn positions (distribución horizontal para 2 jugadores) -constexpr float P1_SPAWN_X_RATIO = 0.33F; // 33% desde izquierda -constexpr float P2_SPAWN_X_RATIO = 0.67F; // 67% desde izquierda -constexpr float SPAWN_Y_RATIO = 0.75F; // 75% desde arriba - -// Continue system behavior -constexpr int CONTINUE_COUNT_START = 9; // Countdown starts at 9 -constexpr float CONTINUE_TICK_DURATION = 1.0F; // Seconds per countdown tick -constexpr int MAX_CONTINUES = 3; // Maximum continues per game -constexpr bool INFINITE_CONTINUES = false; // If true, unlimited continues - -// Continue screen visual configuration -namespace ContinueScreen { -// "CONTINUE" text -constexpr float CONTINUE_TEXT_SCALE = 2.0F; // Text size -constexpr float CONTINUE_TEXT_Y_RATIO = 0.30F; // 35% from top of PLAYAREA - -// Countdown number (9, 8, 7...) -constexpr float COUNTER_TEXT_SCALE = 4.0F; // Text size (large) -constexpr float COUNTER_TEXT_Y_RATIO = 0.50F; // 50% from top of PLAYAREA - -// "CONTINUES LEFT: X" text -constexpr float INFO_TEXT_SCALE = 0.7F; // Text size (small) -constexpr float INFO_TEXT_Y_RATIO = 0.75F; // 65% from top of PLAYAREA -} // namespace ContinueScreen - -// Game Over screen visual configuration -namespace GameOverScreen { -constexpr float TEXT_SCALE = 2.0F; // "GAME OVER" text size -constexpr float TEXT_SPACING = 4.0F; // Character spacing -} // namespace GameOverScreen - -// Stage message configuration (LEVEL_START, LEVEL_COMPLETED) -constexpr float STAGE_MESSAGE_Y_RATIO = 0.25F; // 25% from top of PLAYAREA -constexpr float STAGE_MESSAGE_MAX_WIDTH_RATIO = 0.9F; // 90% of PLAYAREA width -} // namespace Game - -// Física (valores actuales del juego, sincronizados con joc_asteroides.cpp) -namespace Physics { -constexpr float ROTATION_SPEED = 3.14F; // rad/s (~180°/s) -constexpr float ACCELERATION = 400.0F; // px/s² -constexpr float MAX_VELOCITY = 120.0F; // px/s -constexpr float FRICTION = 20.0F; // px/s² -constexpr float ENEMY_SPEED = 2.0F; // unidades/frame -constexpr float BULLET_SPEED = 6.0F; // unidades/frame -constexpr float VELOCITY_SCALE = 20.0F; // factor conversión frame→tiempo - -// Explosions (debris physics) -namespace Debris { -constexpr float VELOCITAT_BASE = 80.0F; // Velocidad inicial (px/s) -constexpr float VARIACIO_VELOCITAT = 40.0F; // ±variació aleatòria (px/s) -constexpr float ACCELERACIO = -60.0F; // Fricció/desacceleració (px/s²) -constexpr float ROTACIO_MIN = 0.1F; // Rotación mínima (rad/s ~5.7°/s) -constexpr float ROTACIO_MAX = 0.3F; // Rotación màxima (rad/s ~17.2°/s) -constexpr float TEMPS_VIDA = 2.0F; // Duració màxima (segons) - enemy/bullet debris -constexpr float TEMPS_VIDA_NAU = 3.0F; // Ship debris lifetime (matches DEATH_DURATION) -constexpr float SHRINK_RATE = 0.5F; // Reducció de mida (factor/s) - -// Herència de velocity angular (trayectorias curvas) -constexpr float FACTOR_HERENCIA_MIN = 0.7F; // Mínimo 70% del drotacio heredat -constexpr float FACTOR_HERENCIA_MAX = 1.0F; // Màxim 100% del drotacio heredat -constexpr float FRICCIO_ANGULAR = 0.5F; // Desacceleració angular (rad/s²) - -// Angular velocity sin for trajectory inheritance -// Excess above this threshold is converted to tangential linear velocity -// Prevents "vortex trap" problem with high-rotation enemies -constexpr float VELOCITAT_ROT_MAX = 1.5F; // rad/s (~86°/s) -} // namespace Debris -} // namespace Physics - -// Matemáticas -namespace Math { -constexpr float PI = std::numbers::pi_v; -} // namespace Math - -// La antigua oscilación CPU (namespace Color) se ha migrado al shader de -// postpro. Los parámetros de flicker / background pulse viven ahora en -// data/config/postfx.yaml y se aplican en shaders/postfx.frag.glsl. - -// Brillantor (control de intensitat per cada type de entidad) -namespace Brightness { -// Brillantor estàtica per entidades de juego (0.0-1.0) -constexpr float NAU = 1.0F; // Màxima visibilitat (player) -constexpr float ENEMIC = 0.7F; // 30% més tènue (destaca menys) -constexpr float BALA = 1.0F; // Brillo a tope (màxima visibilitat) - -// Starfield: gradient segons distancia al centro -// distancia_centre: 0.0 (centro) → 1.0 (vora pantalla) -// brightness = MIN + (MAX - MIN) * distancia_centre -constexpr float STARFIELD_MIN = 0.3F; // Estrelles llunyanes (prop del centro) -constexpr float STARFIELD_MAX = 0.8F; // Estrelles properes (vora pantalla) -} // namespace Brightness - -// Renderització (V-Sync i altres opciones de render) -namespace Rendering { -constexpr int VSYNC_DEFAULT = 1; // 0=disabled, 1=enabled -} // namespace Rendering - -// Audio (sistema de sonido y música) — usado por Audio::Config en init() -namespace Audio { -constexpr bool ENABLED = true; // Audio habilitado por defecto -constexpr float VOLUME = 1.0F; // Volumen maestro (0..1) -constexpr bool MUSIC_ENABLED = true; // Música habilitada -constexpr float MUSIC_VOLUME = 0.8F; // Volumen música (0..1) -constexpr bool SOUND_ENABLED = true; // Efectos habilitados -constexpr float SOUND_VOLUME = 1.0F; // Volumen efectos (0..1) -constexpr float VOLUME_STEP = 0.05F; // Paso UI (5%) -constexpr int FREQUENCY = 48000; // Frecuencia de muestreo (Hz) -constexpr int CROSSFADE_MS = 1500; // Crossfade por defecto entre pistas (ms) -constexpr SDL_AudioFormat FORMAT = SDL_AUDIO_S16; // PCM 16-bit signed nativo -constexpr int CHANNELS = 2; // Estéreo -} // namespace Audio - -// Música (pistas de fondo) -namespace Music { -constexpr const char* GAME_TRACK = "game.ogg"; // Pista de juego -constexpr const char* TITLE_TRACK = "title.ogg"; // Pista de titulo -constexpr int FADE_DURATION_MS = 1000; // Fade out duration -} // namespace Music - -// Efectes de so (sons puntuals) -namespace Sound { -constexpr const char* CONTINUE = "effects/continue.wav"; // Cuenta atras -constexpr const char* EXPLOSION = "effects/explosion.wav"; // Explosión -constexpr const char* EXPLOSION2 = "effects/explosion2.wav"; // Explosión alternativa -constexpr const char* FRIENDLY_FIRE_HIT = "effects/friendly_fire.wav"; // Friendly fire hit -constexpr const char* INIT_HUD = "effects/init_hud.wav"; // Para la animación del HUD -constexpr const char* LASER = "effects/laser_shoot.wav"; // Disparo -constexpr const char* LOGO = "effects/logo.wav"; // Logo -constexpr const char* START = "effects/start.wav"; // El player pulsa START -constexpr const char* GOOD_JOB_COMMANDER = "voices/good_job_commander.wav"; // Voz: "Good job, commander" -} // namespace Sound - -// Controls (mapeo de teclas para los jugadores) -namespace Controls { -namespace P1 { -constexpr SDL_Scancode ROTATE_RIGHT = SDL_SCANCODE_RIGHT; -constexpr SDL_Scancode ROTATE_LEFT = SDL_SCANCODE_LEFT; -constexpr SDL_Scancode THRUST = SDL_SCANCODE_UP; -constexpr SDL_Keycode SHOOT = SDLK_SPACE; -} // namespace P1 - -namespace P2 { -constexpr SDL_Scancode ROTATE_RIGHT = SDL_SCANCODE_D; -constexpr SDL_Scancode ROTATE_LEFT = SDL_SCANCODE_A; -constexpr SDL_Scancode THRUST = SDL_SCANCODE_W; -constexpr SDL_Keycode SHOOT = SDLK_LSHIFT; -} // namespace P2 -} // namespace Controls - -// Enemy type configuration (type de enemigos) -namespace Enemies { -// Pentagon (esquivador - zigzag evasion) -namespace Pentagon { -constexpr float VELOCITAT = 35.0F; // px/s (slightly slower) -constexpr float CANVI_ANGLE_PROB = 0.20F; // 20% per wall hit (frequent zigzag) -constexpr float CANVI_ANGLE_MAX = 1.0F; // Max random angle change (rad) -constexpr float DROTACIO_MIN = 0.75F; // Min visual rotation (rad/s) [+50%] -constexpr float DROTACIO_MAX = 3.75F; // Max visual rotation (rad/s) [+50%] -constexpr const char* SHAPE_FILE = "enemy_pentagon.shp"; -} // namespace Pentagon - -// Cuadrado (perseguidor - tracks player) -namespace Cuadrado { -constexpr float VELOCITAT = 40.0F; // px/s (medium speed) -constexpr float TRACKING_STRENGTH = 0.5F; // Interpolation toward player (0.0-1.0) -constexpr float TRACKING_INTERVAL = 1.0F; // Seconds between angle updates -constexpr float DROTACIO_MIN = 0.3F; // Slow rotation [+50%] -constexpr float DROTACIO_MAX = 1.5F; // [+50%] -constexpr const char* SHAPE_FILE = "enemy_square.shp"; -} // namespace Cuadrado - -// Molinillo (agressiu - fast straight lines, proximity spin-up) -namespace Molinillo { -constexpr float VELOCITAT = 50.0F; // px/s (fastest) -constexpr float CANVI_ANGLE_PROB = 0.05F; // 5% per wall hit (rare direction change) -constexpr float CANVI_ANGLE_MAX = 0.3F; // Small angle adjustments -constexpr float DROTACIO_MIN = 3.0F; // Base rotation (rad/s) [+50%] -constexpr float DROTACIO_MAX = 6.0F; // [+50%] -constexpr float DROTACIO_PROXIMITY_MULTIPLIER = 3.0F; // Spin-up multiplier when near ship -constexpr float PROXIMITY_DISTANCE = 100.0F; // Distance threshold (px) -constexpr const char* SHAPE_FILE = "enemy_pinwheel.shp"; -} // namespace Molinillo - -// Animation parameters (shared) -namespace Animation { -// Palpitation -constexpr float PALPITACIO_TRIGGER_PROB = 0.01F; // 1% chance per second -constexpr float PALPITACIO_DURACIO_MIN = 1.0F; // Min duration (seconds) -constexpr float PALPITACIO_DURACIO_MAX = 3.0F; // Max duration (seconds) -constexpr float PALPITACIO_AMPLITUD_MIN = 0.08F; // Min scale variation -constexpr float PALPITACIO_AMPLITUD_MAX = 0.20F; // Max scale variation -constexpr float PALPITACIO_FREQ_MIN = 1.5F; // Min frequency (Hz) -constexpr float PALPITACIO_FREQ_MAX = 3.0F; // Max frequency (Hz) - -// Rotation acceleration -constexpr float ROTACIO_ACCEL_TRIGGER_PROB = 0.02F; // 2% chance per second [4x more frequent] -constexpr float ROTACIO_ACCEL_DURACIO_MIN = 3.0F; // Min transition time -constexpr float ROTACIO_ACCEL_DURACIO_MAX = 8.0F; // Max transition time -constexpr float ROTACIO_ACCEL_MULTIPLIER_MIN = 0.3F; // Min speed multiplier [more dramatic] -constexpr float ROTACIO_ACCEL_MULTIPLIER_MAX = 4.0F; // Max speed multiplier [more dramatic] -} // namespace Animation - -// Spawn safety and invulnerability system -namespace Spawn { -// Safe spawn distance from player -constexpr float SAFETY_DISTANCE_MULTIPLIER = 3.0F; // 3x ship radius -constexpr float SAFETY_DISTANCE = Defaults::Entities::SHIP_RADIUS * SAFETY_DISTANCE_MULTIPLIER; // 36.0f px -constexpr int MAX_SPAWN_ATTEMPTS = 50; // Max attempts to find safe position - -// Invulnerability system -constexpr float INVULNERABILITY_DURATION = 3.0F; // Seconds -constexpr float INVULNERABILITY_BRIGHTNESS_START = 0.3F; // Dim -constexpr float INVULNERABILITY_BRIGHTNESS_END = 0.7F; // Normal (same as Defaults::Brightness::ENEMIC) -constexpr float INVULNERABILITY_SCALE_START = 0.0F; // Invisible -constexpr float INVULNERABILITY_SCALE_END = 1.0F; // Full size -} // namespace Spawn - -// Scoring system (puntuación per type de enemy) -namespace Scoring { -constexpr int PENTAGON_SCORE = 100; // Pentágono (esquivador, 35 px/s) -constexpr int QUADRAT_SCORE = 150; // Cuadrado (perseguidor, 40 px/s) -constexpr int MOLINILLO_SCORE = 200; // Molinillo (agressiu, 50 px/s) -} // namespace Scoring - -} // namespace Enemies - -// Title scene ship animations (naves 3D flotantes a l'escena de título) -namespace Title { -namespace Ships { -// ============================================================ -// PARÀMETRES BASE (ajustar aquí per experimentar) -// ============================================================ - -// 1. Escala global de las naves -constexpr float SHIP_BASE_SCALE = 2.5F; // Multiplicador (1.0 = mida original del .shp) - -// 2. Altura vertical (cercanía al centro) -// Ratio Y desde el centro de la pantalla (0.0 = centro, 1.0 = bottom de pantalla) -constexpr float TARGET_Y_RATIO = 0.15625F; - -// 3. Radio orbital (distance radial desde centro en coordenadas polares) -constexpr float CLOCK_RADIUS = 150.0F; // Distancia des del centro - -// 4. Ángulos de posición (clock positions en coordenadas polares) -// En coordenadas de pantalla: 0° = derecha, 90° = baix, 180° = izquierda, 270° = dalt -constexpr float CLOCK_8_ANGLE = 150.0F * Math::PI / 180.0F; // 8 o'clock (bottom-left) -constexpr float CLOCK_4_ANGLE = 30.0F * Math::PI / 180.0F; // 4 o'clock (bottom-right) - -// 5. Radio máximo de la shape de la nave (para calcular offset automáticamente) -constexpr float SHIP_MAX_RADIUS = 30.0F; // Radi del cercle circumscrit a ship_starfield.shp - -// 6. Margen de seguridad para offset de entrada -constexpr float ENTRY_OFFSET_MARGIN = 227.5F; // Para offset total de ~340px (ajustado) - -// ============================================================ -// VALORS DERIVATS (calculats automáticoament - NO modificar) -// ============================================================ - -// Centro de la pantalla (point de referència) -constexpr float CENTER_X = Game::WIDTH / 2.0F; // auto-derivado de Game::WIDTH -constexpr float CENTER_Y = Game::HEIGHT / 2.0F; // auto-derivado de Game::HEIGHT - -// Posicions target (calculades dinàmicament des dels parámetros base) -// Nota: std::cos/sin no són constexpr en C++20, pero funcionen en runtime -// Les funciones inline són optimitzades por el compilador (zero overhead) -inline auto p1TargetX() -> float { - return CENTER_X + (CLOCK_RADIUS * std::cos(CLOCK_8_ANGLE)); -} -inline auto p1TargetY() -> float { - return CENTER_Y + ((Game::HEIGHT / 2.0F) * TARGET_Y_RATIO); -} -inline auto p2TargetX() -> float { - return CENTER_X + (CLOCK_RADIUS * std::cos(CLOCK_4_ANGLE)); -} -inline auto p2TargetY() -> float { - return CENTER_Y + ((Game::HEIGHT / 2.0F) * TARGET_Y_RATIO); -} - -// Escales de animación (relatives a SHIP_BASE_SCALE) -constexpr float ENTRY_SCALE_START = 1.5F * SHIP_BASE_SCALE; // Entrada: 50% més grande -constexpr float FLOATING_SCALE = 1.0F * SHIP_BASE_SCALE; // Flotante: scale base - -// Offset de entrada (ajustat automáticoament a l'scale) -// Fórmula: (radi màxim de la ship * scale de entrada) + margen -constexpr float ENTRY_OFFSET = (SHIP_MAX_RADIUS * ENTRY_SCALE_START) + ENTRY_OFFSET_MARGIN; - -// Vec2 de fuga (centro para l'animación de salida) -constexpr float VANISHING_POINT_X = CENTER_X; // auto-derivado de Game::WIDTH -constexpr float VANISHING_POINT_Y = CENTER_Y; // auto-derivado de Game::HEIGHT - -// ============================================================ -// ANIMACIONS (durades, oscil·lacions, delays) -// ============================================================ - -// Durades de animación -constexpr float ENTRY_DURATION = 2.0F; // Entrada (segons) -constexpr float EXIT_DURATION = 1.0F; // Salida (segons) - -// Flotació (oscil·lació reduïda y diferenciada per ship) -constexpr float FLOAT_AMPLITUDE_X = 4.0F; // Amplitud X (píxels) -constexpr float FLOAT_AMPLITUDE_Y = 2.5F; // Amplitud Y (píxels) - -// Freqüències base -constexpr float FLOAT_FREQUENCY_X_BASE = 0.5F; // Hz -constexpr float FLOAT_FREQUENCY_Y_BASE = 0.7F; // Hz -constexpr float FLOAT_PHASE_OFFSET = 1.57F; // π/2 (90°) - -// Delays de entrada (per a entrada escalonada) -constexpr float P1_ENTRY_DELAY = 0.0F; // P1 entra immediatament -constexpr float P2_ENTRY_DELAY = 0.5F; // P2 entra 0.5s después - -// Delay global antes de start l'animación de entrada al state MAIN -constexpr float ENTRANCE_DELAY = 5.0F; // Temps de espera antes que las naves entrin - -// Multiplicadors de freqüència para cada ship (variació sutil ±12%) -constexpr float P1_FREQUENCY_MULTIPLIER = 0.88F; // 12% més lenta -constexpr float P2_FREQUENCY_MULTIPLIER = 1.12F; // 12% més ràpida - -} // namespace Ships - -namespace Layout { -// Posicions verticals (anclatges des del TOP de pantalla lógica, 0.0-1.0) -constexpr float LOGO_POS = 0.20F; // Logo "ORNI" -constexpr float PRESS_START_POS = 0.75F; // "PRESS START TO PLAY" -constexpr float COPYRIGHT1_POS = 0.90F; // Primera línia copyright - -// Separacions relatives (proporció respecte Game::HEIGHT = 480px) -constexpr float LOGO_LINE_SPACING = 0.02F; // Entre "ORNI" i "ATTACK!" (10px) -constexpr float COPYRIGHT_LINE_SPACING = 0.0F; // Entre línies copyright (5px) - -// Factors de scale -constexpr float LOGO_SCALE = 0.6F; // Escala "ORNI ATTACK!" -constexpr float PRESS_START_SCALE = 1.0F; // Escala "PRESS START TO PLAY" -constexpr float COPYRIGHT_SCALE = 0.5F; // Escala copyright -constexpr float JAILGAMES_SCALE = 0.25F; // Escala del logo JAILGAMES pequeño sobre el copyright - -// Separación entre el logo JAILGAMES y la línea de copyright (proporción de Game::HEIGHT). -constexpr float JAILGAMES_COPYRIGHT_GAP = 0.015F; - -// Espaiat entre caràcters (usado per VectorText) -constexpr float TEXT_SPACING = 2.0F; -} // namespace Layout -} // namespace Title - -// Floating score numbers (números flotantes de puntuación) -namespace FloatingScore { -constexpr float LIFETIME = 2.0F; // Duració màxima (segons) -constexpr float VELOCITY_Y = -30.0F; // Velocidad vertical (px/s, negatiu = amunt) -constexpr float VELOCITY_X = 0.0F; // Velocidad horizontal (px/s) -constexpr float SCALE = 0.45F; // Escala del text (0.6 = 60% del marcador) -constexpr float SPACING = 0.0F; // Espaiat entre caràcters -constexpr int MAX_CONCURRENT = 15; // Pool size (= MAX_ORNIS) -} // namespace FloatingScore + // Configuración de ventana + namespace Window { + constexpr int WIDTH = 1280; + constexpr int HEIGHT = 720; + constexpr int MIN_WIDTH = 640; // Mínimo: mitad del baseline (16:9) + constexpr int MIN_HEIGHT = 360; + // Zoom system + constexpr float BASE_ZOOM = 1.0F; // 1280x720 baseline (16:9) + constexpr float MIN_ZOOM = 0.5F; // 640x360 minimum + constexpr float ZOOM_INCREMENT = 0.1F; // 10% steps (F1/F2) + constexpr bool FULLSCREEN = true; // Pantalla completa activada por defecto + } // namespace Window + + // Dimensiones base del juego (coordenadas lógicas, 16:9) + namespace Game { + constexpr int WIDTH = 1280; + constexpr int HEIGHT = 720; + } // namespace Game + + // Zones del juego (SDL_FRect con cálculos automáticos basat en porcentajes) + namespace Zones { + // --- CONFIGURACIÓ DE PORCENTATGES --- + // Todas las zones definides como a porcentajes de Game::WIDTH (640) i Game::HEIGHT (480) + + // Percentatges de height (divisió vertical) + constexpr float SCOREBOARD_TOP_HEIGHT_PERCENT = 0.02F; // 10% superior + constexpr float MAIN_PLAYAREA_HEIGHT_PERCENT = 0.88F; // 80% central + constexpr float SCOREBOARD_BOTTOM_HEIGHT_PERCENT = 0.10F; // 10% inferior + + // Padding horizontal para PLAYAREA (dentro de MAIN_PLAYAREA) + constexpr float PLAYAREA_PADDING_HORIZONTAL_PERCENT = 0.015F; // 5% a cada costat + + // --- CÀLCULS AUTOMÀTICS DE PÍXELS --- + // Cálculos automáticos a partir dels porcentajes + + // Alçades + constexpr float SCOREBOARD_TOP_H = Game::HEIGHT * SCOREBOARD_TOP_HEIGHT_PERCENT; + constexpr float MAIN_PLAYAREA_H = Game::HEIGHT * MAIN_PLAYAREA_HEIGHT_PERCENT; + constexpr float SCOREBOARD_BOTTOM_H = Game::HEIGHT * SCOREBOARD_BOTTOM_HEIGHT_PERCENT; + + // Posicions Y + constexpr float SCOREBOARD_TOP_Y = 0.0F; + constexpr float MAIN_PLAYAREA_Y = SCOREBOARD_TOP_H; + constexpr float SCOREBOARD_BOTTOM_Y = MAIN_PLAYAREA_Y + MAIN_PLAYAREA_H; + + // Padding horizontal de PLAYAREA + constexpr float PLAYAREA_PADDING_H = Game::WIDTH * PLAYAREA_PADDING_HORIZONTAL_PERCENT; + + // --- ZONES FINALS (SDL_FRect) --- + + // Marcador superior (reservado para futuro uso) + // Ocupa el 2% superior + constexpr SDL_FRect SCOREBOARD_TOP = { + 0.0F, // x = 0.0 + SCOREBOARD_TOP_Y, // y = 0.0 + static_cast(Game::WIDTH), // ancho completo + SCOREBOARD_TOP_H // alto + }; + + // Área de juego principal (contenedor del 80% central, sin padding) + // Ocupa el 88% central, ancho completo + constexpr SDL_FRect MAIN_PLAYAREA = { + 0.0F, // x = 0.0 + MAIN_PLAYAREA_Y, // debajo del scoreboard superior + static_cast(Game::WIDTH), // ancho completo + MAIN_PLAYAREA_H // alto + }; + + // Zona de juego real (con padding horizontal del 5%) + // Ocupa: dentro de MAIN_PLAYAREA, con márgenes laterales + // Se utiliza para límites del juego, colisiones, spawn + constexpr SDL_FRect PLAYAREA = { + PLAYAREA_PADDING_H, // padding horizontal + MAIN_PLAYAREA_Y, // debajo del scoreboard superior (igual que MAIN_PLAYAREA) + Game::WIDTH - (2.0F * PLAYAREA_PADDING_H), // ancho con padding + MAIN_PLAYAREA_H // alto (igual que MAIN_PLAYAREA) + }; + + // Marcador inferior (marcador actual) + // Ocupa el 10% inferior + constexpr SDL_FRect SCOREBOARD = { + 0.0F, // x = 0.0 + SCOREBOARD_BOTTOM_Y, // fondo + static_cast(Game::WIDTH), // ancho completo + SCOREBOARD_BOTTOM_H // alto + }; + + // Padding horizontal del marcador (para alinear zonas izquierda/derecha con PLAYAREA) + constexpr float SCOREBOARD_PADDING_H = 0.0F; // Game::WIDTH * 0.015f; + } // namespace Zones + + // Objetos del juego + namespace Entities { + constexpr int MAX_ORNIS = 15; + constexpr int MAX_BALES = 3; + + constexpr float SHIP_RADIUS = 12.0F; + constexpr float ENEMY_RADIUS = 20.0F; + constexpr float BULLET_RADIUS = 3.0F; + } // namespace Entities + + // Paleta semántica por tipo de entidad. Si una entity declara color, lo + // pasa al pipeline con alpha=255 (sentinela "color válido"); si no, se + // usa el color global del oscilador (g_current_line_color). + namespace Palette { + constexpr SDL_Color SHIP = {.r = 255, .g = 255, .b = 255, .a = 255}; // Blanco neutro + constexpr SDL_Color BULLET = {.r = 120, .g = 255, .b = 140, .a = 255}; // Verde laser + constexpr SDL_Color PENTAGON = {.r = 120, .g = 170, .b = 255, .a = 255}; // Azul "esquivador" + constexpr SDL_Color QUADRAT = {.r = 255, .g = 110, .b = 110, .a = 255}; // Rojo "tank" + constexpr SDL_Color MOLINILLO = {.r = 255, .g = 130, .b = 255, .a = 255}; // Magenta agresivo + } // namespace Palette + + // Ship (nave del player) + namespace Ship { + // Invulnerabilidad post-respawn + constexpr float INVULNERABILITY_DURATION = 3.0F; // Segundos de invulnerabilidad + + // Parpadeo visual durante invulnerabilidad + constexpr float BLINK_VISIBLE_TIME = 0.1F; // Tiempo visible (segundos) + constexpr float BLINK_INVISIBLE_TIME = 0.1F; // Tiempo invisible (segundos) + // Frecuencia total: 0.2s/ciclo = 5 Hz (~15 parpadeos en 3s) + } // namespace Ship + + // Game rules (lives, respawn, game over) + namespace Game { + constexpr int STARTING_LIVES = 3; // Initial lives + constexpr float DEATH_DURATION = 3.0F; // Seconds of death animation + constexpr float GAME_OVER_DURATION = 5.0F; // Seconds to display game over + constexpr float COLLISION_SHIP_ENEMY_AMPLIFIER = 0.80F; // 80% hitbox (generous) + constexpr float COLLISION_BULLET_ENEMY_AMPLIFIER = 1.15F; // 115% hitbox (generous) + + // Friendly fire system + constexpr bool FRIENDLY_FIRE_ENABLED = true; // Activar friendly fire + constexpr float COLLISION_BULLET_PLAYER_AMPLIFIER = 1.0F; // Hitbox exacto (100%) + constexpr float BULLET_GRACE_PERIOD = 0.2F; // Inmunidad post-disparo (s) + + // Transición LEVEL_START (mensajes aleatorios PRE-level) + constexpr float LEVEL_START_DURATION = 3.0F; // Duración total + constexpr float LEVEL_START_TYPING_RATIO = 0.3F; // 30% escribiendo, 70% mostrando + + // Transición LEVEL_COMPLETED (mensaje "GOOD JOB COMMANDER!") + constexpr float LEVEL_COMPLETED_DURATION = 3.0F; // Duración total + constexpr float LEVEL_COMPLETED_TYPING_RATIO = 0.0F; // 0.0 = sin typewriter (directo) + + // Transición INIT_HUD (animación inicial del HUD) + constexpr float INIT_HUD_DURATION = 3.0F; // Duración total del estado + + // Ratios de animación (inicio y fin como porcentajes del tiempo total) + // RECT (rectángulo de márgenes) + constexpr float INIT_HUD_RECT_RATIO_INIT = 0.30F; + constexpr float INIT_HUD_RECT_RATIO_END = 0.85F; + + // SCORE (marcador de puntuación) + constexpr float INIT_HUD_SCORE_RATIO_INIT = 0.60F; + constexpr float INIT_HUD_SCORE_RATIO_END = 0.90F; + + // SHIP1 (nave player 1) + constexpr float INIT_HUD_SHIP1_RATIO_INIT = 0.0F; + constexpr float INIT_HUD_SHIP1_RATIO_END = 1.0F; + + // SHIP2 (nave player 2) + constexpr float INIT_HUD_SHIP2_RATIO_INIT = 0.20F; + constexpr float INIT_HUD_SHIP2_RATIO_END = 1.0F; + + // Posición inicial de la nave en INIT_HUD (75% de altura de zona de juego) + constexpr float INIT_HUD_SHIP_START_Y_RATIO = 0.75F; // 75% desde el top de PLAYAREA + + // Spawn positions (distribución horizontal para 2 jugadores) + constexpr float P1_SPAWN_X_RATIO = 0.33F; // 33% desde izquierda + constexpr float P2_SPAWN_X_RATIO = 0.67F; // 67% desde izquierda + constexpr float SPAWN_Y_RATIO = 0.75F; // 75% desde arriba + + // Continue system behavior + constexpr int CONTINUE_COUNT_START = 9; // Countdown starts at 9 + constexpr float CONTINUE_TICK_DURATION = 1.0F; // Seconds per countdown tick + constexpr int MAX_CONTINUES = 3; // Maximum continues per game + constexpr bool INFINITE_CONTINUES = false; // If true, unlimited continues + + // Continue screen visual configuration + namespace ContinueScreen { + // "CONTINUE" text + constexpr float CONTINUE_TEXT_SCALE = 2.0F; // Text size + constexpr float CONTINUE_TEXT_Y_RATIO = 0.30F; // 35% from top of PLAYAREA + + // Countdown number (9, 8, 7...) + constexpr float COUNTER_TEXT_SCALE = 4.0F; // Text size (large) + constexpr float COUNTER_TEXT_Y_RATIO = 0.50F; // 50% from top of PLAYAREA + + // "CONTINUES LEFT: X" text + constexpr float INFO_TEXT_SCALE = 0.7F; // Text size (small) + constexpr float INFO_TEXT_Y_RATIO = 0.75F; // 65% from top of PLAYAREA + } // namespace ContinueScreen + + // Game Over screen visual configuration + namespace GameOverScreen { + constexpr float TEXT_SCALE = 2.0F; // "GAME OVER" text size + constexpr float TEXT_SPACING = 4.0F; // Character spacing + } // namespace GameOverScreen + + // Stage message configuration (LEVEL_START, LEVEL_COMPLETED) + constexpr float STAGE_MESSAGE_Y_RATIO = 0.25F; // 25% from top of PLAYAREA + constexpr float STAGE_MESSAGE_MAX_WIDTH_RATIO = 0.9F; // 90% of PLAYAREA width + } // namespace Game + + // Física del control de la nau (px/s, rad/s) + namespace Physics { + constexpr float ROTATION_SPEED = 3.14F; // rad/s (~180°/s) + constexpr float ACCELERATION = 400.0F; // px/s² + constexpr float MAX_VELOCITY = 120.0F; // px/s + constexpr float FRICTION = 20.0F; // px/s² + + // Explosions (debris physics) + namespace Debris { + constexpr float VELOCITAT_BASE = 80.0F; // Velocidad inicial (px/s) + constexpr float VARIACIO_VELOCITAT = 40.0F; // ±variació aleatòria (px/s) + constexpr float ACCELERACIO = -60.0F; // Fricció/desacceleració (px/s²) + constexpr float ROTACIO_MIN = 0.1F; // Rotación mínima (rad/s ~5.7°/s) + constexpr float ROTACIO_MAX = 0.3F; // Rotación màxima (rad/s ~17.2°/s) + constexpr float TEMPS_VIDA = 2.0F; // Duració màxima (segons) - enemy/bullet debris + constexpr float TEMPS_VIDA_NAU = 3.0F; // Ship debris lifetime (matches DEATH_DURATION) + constexpr float SHRINK_RATE = 0.5F; // Reducció de mida (factor/s) + + // Herència de velocity angular (trayectorias curvas) + constexpr float FACTOR_HERENCIA_MIN = 0.7F; // Mínimo 70% del drotacio heredat + constexpr float FACTOR_HERENCIA_MAX = 1.0F; // Màxim 100% del drotacio heredat + constexpr float FRICCIO_ANGULAR = 0.5F; // Desacceleració angular (rad/s²) + + // Angular velocity sin for trajectory inheritance + // Excess above this threshold is converted to tangential linear velocity + // Prevents "vortex trap" problem with high-rotation enemies + constexpr float VELOCITAT_ROT_MAX = 1.5F; // rad/s (~86°/s) + } // namespace Debris + } // namespace Physics + + // Matemáticas + namespace Math { + constexpr float PI = std::numbers::pi_v; + } // namespace Math + + // La antigua oscilación CPU (namespace Color) se ha migrado al shader de + // postpro. Los parámetros de flicker / background pulse viven ahora en + // data/config/postfx.yaml y se aplican en shaders/postfx.frag.glsl. + + // Brillantor (control de intensitat per cada type de entidad) + namespace Brightness { + // Brillantor estàtica per entidades de juego (0.0-1.0) + constexpr float NAU = 1.0F; // Màxima visibilitat (player) + constexpr float ENEMIC = 0.7F; // 30% més tènue (destaca menys) + constexpr float BALA = 1.0F; // Brillo a tope (màxima visibilitat) + + // Starfield: gradient segons distancia al centro + // distancia_centre: 0.0 (centro) → 1.0 (vora pantalla) + // brightness = MIN + (MAX - MIN) * distancia_centre + constexpr float STARFIELD_MIN = 0.3F; // Estrelles llunyanes (prop del centro) + constexpr float STARFIELD_MAX = 0.8F; // Estrelles properes (vora pantalla) + } // namespace Brightness + + // Renderització (V-Sync i altres opciones de render) + namespace Rendering { + constexpr int VSYNC_DEFAULT = 1; // 0=disabled, 1=enabled + } // namespace Rendering + + // Audio (sistema de sonido y música) — usado por Audio::Config en init() + namespace Audio { + constexpr bool ENABLED = true; // Audio habilitado por defecto + constexpr float VOLUME = 1.0F; // Volumen maestro (0..1) + constexpr bool MUSIC_ENABLED = true; // Música habilitada + constexpr float MUSIC_VOLUME = 0.8F; // Volumen música (0..1) + constexpr bool SOUND_ENABLED = true; // Efectos habilitados + constexpr float SOUND_VOLUME = 1.0F; // Volumen efectos (0..1) + constexpr float VOLUME_STEP = 0.05F; // Paso UI (5%) + constexpr int FREQUENCY = 48000; // Frecuencia de muestreo (Hz) + constexpr int CROSSFADE_MS = 1500; // Crossfade por defecto entre pistas (ms) + constexpr SDL_AudioFormat FORMAT = SDL_AUDIO_S16; // PCM 16-bit signed nativo + constexpr int CHANNELS = 2; // Estéreo + } // namespace Audio + + // Música (pistas de fondo) + namespace Music { + constexpr const char* GAME_TRACK = "game.ogg"; // Pista de juego + constexpr const char* TITLE_TRACK = "title.ogg"; // Pista de titulo + constexpr int FADE_DURATION_MS = 1000; // Fade out duration + } // namespace Music + + // Efectes de so (sons puntuals) + namespace Sound { + constexpr const char* CONTINUE = "effects/continue.wav"; // Cuenta atras + constexpr const char* EXPLOSION = "effects/explosion.wav"; // Explosión + constexpr const char* EXPLOSION2 = "effects/explosion2.wav"; // Explosión alternativa + constexpr const char* FRIENDLY_FIRE_HIT = "effects/friendly_fire.wav"; // Friendly fire hit + constexpr const char* INIT_HUD = "effects/init_hud.wav"; // Para la animación del HUD + constexpr const char* LASER = "effects/laser_shoot.wav"; // Disparo + constexpr const char* LOGO = "effects/logo.wav"; // Logo + constexpr const char* START = "effects/start.wav"; // El player pulsa START + constexpr const char* GOOD_JOB_COMMANDER = "voices/good_job_commander.wav"; // Voz: "Good job, commander" + } // namespace Sound + + // Controls (mapeo de teclas para los jugadores) + namespace Controls { + namespace P1 { + constexpr SDL_Scancode ROTATE_RIGHT = SDL_SCANCODE_RIGHT; + constexpr SDL_Scancode ROTATE_LEFT = SDL_SCANCODE_LEFT; + constexpr SDL_Scancode THRUST = SDL_SCANCODE_UP; + constexpr SDL_Keycode SHOOT = SDLK_SPACE; + } // namespace P1 + + namespace P2 { + constexpr SDL_Scancode ROTATE_RIGHT = SDL_SCANCODE_D; + constexpr SDL_Scancode ROTATE_LEFT = SDL_SCANCODE_A; + constexpr SDL_Scancode THRUST = SDL_SCANCODE_W; + constexpr SDL_Keycode SHOOT = SDLK_LSHIFT; + } // namespace P2 + } // namespace Controls + + // Enemy type configuration (type de enemigos) + namespace Enemies { + // Pentagon (esquivador - zigzag evasion) + namespace Pentagon { + constexpr float VELOCITAT = 35.0F; // px/s (slightly slower) + constexpr float CANVI_ANGLE_PROB = 0.20F; // 20% per wall hit (frequent zigzag) + constexpr float CANVI_ANGLE_MAX = 1.0F; // Max random angle change (rad) + constexpr float DROTACIO_MIN = 0.75F; // Min visual rotation (rad/s) [+50%] + constexpr float DROTACIO_MAX = 3.75F; // Max visual rotation (rad/s) [+50%] + constexpr const char* SHAPE_FILE = "enemy_pentagon.shp"; + } // namespace Pentagon + + // Cuadrado (perseguidor - tracks player) + namespace Cuadrado { + constexpr float VELOCITAT = 40.0F; // px/s (medium speed) + constexpr float TRACKING_STRENGTH = 0.5F; // Interpolation toward player (0.0-1.0) + constexpr float TRACKING_INTERVAL = 1.0F; // Seconds between angle updates + constexpr float DROTACIO_MIN = 0.3F; // Slow rotation [+50%] + constexpr float DROTACIO_MAX = 1.5F; // [+50%] + constexpr const char* SHAPE_FILE = "enemy_square.shp"; + } // namespace Cuadrado + + // Molinillo (agressiu - fast straight lines, proximity spin-up) + namespace Molinillo { + constexpr float VELOCITAT = 50.0F; // px/s (fastest) + constexpr float CANVI_ANGLE_PROB = 0.05F; // 5% per wall hit (rare direction change) + constexpr float CANVI_ANGLE_MAX = 0.3F; // Small angle adjustments + constexpr float DROTACIO_MIN = 3.0F; // Base rotation (rad/s) [+50%] + constexpr float DROTACIO_MAX = 6.0F; // [+50%] + constexpr float DROTACIO_PROXIMITY_MULTIPLIER = 3.0F; // Spin-up multiplier when near ship + constexpr float PROXIMITY_DISTANCE = 100.0F; // Distance threshold (px) + constexpr const char* SHAPE_FILE = "enemy_pinwheel.shp"; + } // namespace Molinillo + + // Animation parameters (shared) + namespace Animation { + // Palpitation + constexpr float PALPITACIO_TRIGGER_PROB = 0.01F; // 1% chance per second + constexpr float PALPITACIO_DURACIO_MIN = 1.0F; // Min duration (seconds) + constexpr float PALPITACIO_DURACIO_MAX = 3.0F; // Max duration (seconds) + constexpr float PALPITACIO_AMPLITUD_MIN = 0.08F; // Min scale variation + constexpr float PALPITACIO_AMPLITUD_MAX = 0.20F; // Max scale variation + constexpr float PALPITACIO_FREQ_MIN = 1.5F; // Min frequency (Hz) + constexpr float PALPITACIO_FREQ_MAX = 3.0F; // Max frequency (Hz) + + // Rotation acceleration + constexpr float ROTACIO_ACCEL_TRIGGER_PROB = 0.02F; // 2% chance per second [4x more frequent] + constexpr float ROTACIO_ACCEL_DURACIO_MIN = 3.0F; // Min transition time + constexpr float ROTACIO_ACCEL_DURACIO_MAX = 8.0F; // Max transition time + constexpr float ROTACIO_ACCEL_MULTIPLIER_MIN = 0.3F; // Min speed multiplier [more dramatic] + constexpr float ROTACIO_ACCEL_MULTIPLIER_MAX = 4.0F; // Max speed multiplier [more dramatic] + } // namespace Animation + + // Spawn safety and invulnerability system + namespace Spawn { + // Safe spawn distance from player + constexpr float SAFETY_DISTANCE_MULTIPLIER = 3.0F; // 3x ship radius + constexpr float SAFETY_DISTANCE = Defaults::Entities::SHIP_RADIUS * SAFETY_DISTANCE_MULTIPLIER; // 36.0f px + constexpr int MAX_SPAWN_ATTEMPTS = 50; // Max attempts to find safe position + + // Invulnerability system + constexpr float INVULNERABILITY_DURATION = 3.0F; // Seconds + constexpr float INVULNERABILITY_BRIGHTNESS_START = 0.3F; // Dim + constexpr float INVULNERABILITY_BRIGHTNESS_END = 0.7F; // Normal (same as Defaults::Brightness::ENEMIC) + constexpr float INVULNERABILITY_SCALE_START = 0.0F; // Invisible + constexpr float INVULNERABILITY_SCALE_END = 1.0F; // Full size + } // namespace Spawn + + // Scoring system (puntuación per type de enemy) + namespace Scoring { + constexpr int PENTAGON_SCORE = 100; // Pentágono (esquivador, 35 px/s) + constexpr int QUADRAT_SCORE = 150; // Cuadrado (perseguidor, 40 px/s) + constexpr int MOLINILLO_SCORE = 200; // Molinillo (agressiu, 50 px/s) + } // namespace Scoring + + } // namespace Enemies + + // Title scene ship animations (naves 3D flotantes a l'escena de título) + namespace Title { + namespace Ships { + // ============================================================ + // PARÀMETRES BASE (ajustar aquí per experimentar) + // ============================================================ + + // 1. Escala global de las naves + constexpr float SHIP_BASE_SCALE = 2.5F; // Multiplicador (1.0 = mida original del .shp) + + // 2. Altura vertical (cercanía al centro) + // Ratio Y desde el centro de la pantalla (0.0 = centro, 1.0 = bottom de pantalla) + constexpr float TARGET_Y_RATIO = 0.15625F; + + // 3. Radio orbital (distance radial desde centro en coordenadas polares) + constexpr float CLOCK_RADIUS = 150.0F; // Distancia des del centro + + // 4. Ángulos de posición (clock positions en coordenadas polares) + // En coordenadas de pantalla: 0° = derecha, 90° = baix, 180° = izquierda, 270° = dalt + constexpr float CLOCK_8_ANGLE = 150.0F * Math::PI / 180.0F; // 8 o'clock (bottom-left) + constexpr float CLOCK_4_ANGLE = 30.0F * Math::PI / 180.0F; // 4 o'clock (bottom-right) + + // 5. Radio máximo de la shape de la nave (para calcular offset automáticamente) + constexpr float SHIP_MAX_RADIUS = 30.0F; // Radi del cercle circumscrit a ship_starfield.shp + + // 6. Margen de seguridad para offset de entrada + constexpr float ENTRY_OFFSET_MARGIN = 227.5F; // Para offset total de ~340px (ajustado) + + // ============================================================ + // VALORS DERIVATS (calculats automáticoament - NO modificar) + // ============================================================ + + // Centro de la pantalla (point de referència) + constexpr float CENTER_X = Game::WIDTH / 2.0F; // auto-derivado de Game::WIDTH + constexpr float CENTER_Y = Game::HEIGHT / 2.0F; // auto-derivado de Game::HEIGHT + + // Posicions target (calculades dinàmicament des dels parámetros base) + // Nota: std::cos/sin no són constexpr en C++20, pero funcionen en runtime + // Les funciones inline són optimitzades por el compilador (zero overhead) + inline auto p1TargetX() -> float { + return CENTER_X + (CLOCK_RADIUS * std::cos(CLOCK_8_ANGLE)); + } + inline auto p1TargetY() -> float { + return CENTER_Y + ((Game::HEIGHT / 2.0F) * TARGET_Y_RATIO); + } + inline auto p2TargetX() -> float { + return CENTER_X + (CLOCK_RADIUS * std::cos(CLOCK_4_ANGLE)); + } + inline auto p2TargetY() -> float { + return CENTER_Y + ((Game::HEIGHT / 2.0F) * TARGET_Y_RATIO); + } + + // Escales de animación (relatives a SHIP_BASE_SCALE) + constexpr float ENTRY_SCALE_START = 1.5F * SHIP_BASE_SCALE; // Entrada: 50% més grande + constexpr float FLOATING_SCALE = 1.0F * SHIP_BASE_SCALE; // Flotante: scale base + + // Offset de entrada (ajustat automáticoament a l'scale) + // Fórmula: (radi màxim de la ship * scale de entrada) + margen + constexpr float ENTRY_OFFSET = (SHIP_MAX_RADIUS * ENTRY_SCALE_START) + ENTRY_OFFSET_MARGIN; + + // Vec2 de fuga (centro para l'animación de salida) + constexpr float VANISHING_POINT_X = CENTER_X; // auto-derivado de Game::WIDTH + constexpr float VANISHING_POINT_Y = CENTER_Y; // auto-derivado de Game::HEIGHT + + // ============================================================ + // ANIMACIONS (durades, oscil·lacions, delays) + // ============================================================ + + // Durades de animación + constexpr float ENTRY_DURATION = 2.0F; // Entrada (segons) + constexpr float EXIT_DURATION = 1.0F; // Salida (segons) + + // Flotació (oscil·lació reduïda y diferenciada per ship) + constexpr float FLOAT_AMPLITUDE_X = 4.0F; // Amplitud X (píxels) + constexpr float FLOAT_AMPLITUDE_Y = 2.5F; // Amplitud Y (píxels) + + // Freqüències base + constexpr float FLOAT_FREQUENCY_X_BASE = 0.5F; // Hz + constexpr float FLOAT_FREQUENCY_Y_BASE = 0.7F; // Hz + constexpr float FLOAT_PHASE_OFFSET = 1.57F; // π/2 (90°) + + // Delays de entrada (per a entrada escalonada) + constexpr float P1_ENTRY_DELAY = 0.0F; // P1 entra immediatament + constexpr float P2_ENTRY_DELAY = 0.5F; // P2 entra 0.5s después + + // Delay global antes de start l'animación de entrada al state MAIN + constexpr float ENTRANCE_DELAY = 5.0F; // Temps de espera antes que las naves entrin + + // Multiplicadors de freqüència para cada ship (variació sutil ±12%) + constexpr float P1_FREQUENCY_MULTIPLIER = 0.88F; // 12% més lenta + constexpr float P2_FREQUENCY_MULTIPLIER = 1.12F; // 12% més ràpida + + } // namespace Ships + + namespace Layout { + // Posicions verticals (anclatges des del TOP de pantalla lógica, 0.0-1.0) + constexpr float LOGO_POS = 0.20F; // Logo "ORNI" + constexpr float PRESS_START_POS = 0.75F; // "PRESS START TO PLAY" + constexpr float COPYRIGHT1_POS = 0.90F; // Primera línia copyright + + // Separacions relatives (proporció respecte Game::HEIGHT = 480px) + constexpr float LOGO_LINE_SPACING = 0.02F; // Entre "ORNI" i "ATTACK!" (10px) + constexpr float COPYRIGHT_LINE_SPACING = 0.0F; // Entre línies copyright (5px) + + // Factors de scale + constexpr float LOGO_SCALE = 0.6F; // Escala "ORNI ATTACK!" + constexpr float PRESS_START_SCALE = 1.0F; // Escala "PRESS START TO PLAY" + constexpr float COPYRIGHT_SCALE = 0.5F; // Escala copyright + constexpr float JAILGAMES_SCALE = 0.25F; // Escala del logo JAILGAMES pequeño sobre el copyright + + // Separación entre el logo JAILGAMES y la línea de copyright (proporción de Game::HEIGHT). + constexpr float JAILGAMES_COPYRIGHT_GAP = 0.015F; + + // Espaiat entre caràcters (usado per VectorText) + constexpr float TEXT_SPACING = 2.0F; + } // namespace Layout + } // namespace Title + + // Floating score numbers (números flotantes de puntuación) + namespace FloatingScore { + constexpr float LIFETIME = 2.0F; // Duració màxima (segons) + constexpr float VELOCITY_Y = -30.0F; // Velocidad vertical (px/s, negatiu = amunt) + constexpr float VELOCITY_X = 0.0F; // Velocidad horizontal (px/s) + constexpr float SCALE = 0.45F; // Escala del text (0.6 = 60% del marcador) + constexpr float SPACING = 0.0F; // Espaiat entre caràcters + constexpr int MAX_CONCURRENT = 15; // Pool size (= MAX_ORNIS) + } // namespace FloatingScore } // namespace Defaults