Fase 1e: cierre de naming sweep (#pragma once, locals, comentarios castellano)
Tres tareas de pulido para cerrar la Fase 1 por completo: #pragma once uniforme: - sdl_manager.hpp y game_scene.hpp pasan de #ifndef/#define guards a #pragma once. Los archivos externos (stb_vorbis.h, fkyaml_node.hpp) se mantienen intactos (codigo de terceros). Variables locales y parametros restantes (catalan -> ingles): - fitxer -> file, moviment -> movement, inici -> start - comptador -> counter, escalada -> scaled - missatges -> messages, llista -> list - alçada -> height, amplada -> width, llargada -> length - origen -> origin, distancia -> distance, valor -> value, desti -> target - neteja -> clear, presenta -> present (SDLManager) - total_enemics -> total_enemies, configurar -> configure, iniciar -> start Comentarios catalan -> castellano: - Cabeceras de fichero actualizadas con nombres nuevos (escena_joc.hpp -> game_scene.hpp, etc.) - Palabras tecnicas: trasllacio->traslacion, col-lisio->colision, inicialitzacio->inicializacion, posicio->posicion, rotacio->rotacion, velocitat->velocidad, acceleracio->aceleracion, explosio->explosion, renderitzat->renderizado, calcul->calculo, transicio->transicion, comprovacio->comprobacion, substitucio->sustitucion, utilitzacio->utilizacion, opcio->opcion, configuracio->configuracion, funcio->funcion, distancia, animacio->animacion - Determinantes y conectores: aquest->este, aquesta->esta, amb->con, sense->sin, pero->pero, mai->nunca, nomes->solo, tambe->tambien, sempre->siempre, ja->ya, mateix->mismo, vegada->vez, dintre->dentro, fora->fuera, dreta->derecha, esquerra->izquierda, sortir->salir, sortida->salida, petit->pequeno, gran->grande, nou->nuevo, vell->viejo, molt->mucho, els->los, les->las, totes les->todas las, d'->de, com->como, quan->cuando, mentre->mientras, despres->despues, abans->antes, durant->durante, fins->hasta, encara->aun, llavors->entonces, aixi->asi, perque->porque - Sustantivos: classe->clase, metode->metodo, parametre->parametro, versio->version, entitat->entidad, joc->juego, nivell->nivel, enemic->enemigo, naus->naves, bales->balas, fitxer->archivo, pentagon->pentagono, pun- tuacio->puntuacion, flotant->flotante, titol->titulo, objectiu->objetivo, mostra->muestra, tipus->tipo Strings literales preservados en valenciano segun decision del usuario: el texto del HUD del juego (puntuaciones, mensajes en pantalla, archivo de config) se mantiene en valenciano original. 70 fitxers tocats, +1117 / -1123. Compila i enllaca. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -64,7 +64,7 @@ void Audio::playMusic(const std::string& name, const int loop) {
|
||||
// Llamada al motor para reproducir la nueva pista
|
||||
JA_PlayMusic(resource, loop);
|
||||
|
||||
// Actualizar estado y metadatos después de iniciar con éxito
|
||||
// Actualizar estado y metadatos después de start con éxito
|
||||
music_.name = name;
|
||||
music_.loop = new_loop;
|
||||
music_.state = MusicState::PLAYING;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// audio_cache.cpp - Implementació del caché de sons i música
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "core/audio/audio_cache.hpp"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
|
||||
// Inicialització de variables estàtiques
|
||||
// Inicialización de variables estàtiques
|
||||
std::unordered_map<std::string, JA_Sound_t*> AudioCache::sounds_;
|
||||
std::unordered_map<std::string, JA_Music_t*> AudioCache::musics_;
|
||||
std::string AudioCache::sounds_base_path_ = "data/sounds/";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// audio_cache.hpp - Caché simplificado de sonidos y música
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ inline JA_Music_t* JA_LoadMusic(const Uint8* buffer, Uint32 length) {
|
||||
}
|
||||
|
||||
inline JA_Music_t* JA_LoadMusic(const char* filename) {
|
||||
// [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid.
|
||||
// [RZC 28/08/22] Carreguem primer el arxiu en memòria y después el descomprimim. Es algo més rapid.
|
||||
FILE* f = fopen(filename, "rb");
|
||||
if (!f) return NULL; // Añadida comprobación de apertura
|
||||
fseek(f, 0, SEEK_END);
|
||||
|
||||
+58
-58
@@ -19,27 +19,27 @@ constexpr float ZOOM_INCREMENT = 0.1F; // 10% steps (F1/F2)
|
||||
constexpr bool FULLSCREEN = true; // Pantalla completa activadapor defecto
|
||||
} // namespace Window
|
||||
|
||||
// Dimensions base del joc (coordenades lògiques)
|
||||
// Dimensions base del juego (coordenades lògiques)
|
||||
namespace Game {
|
||||
constexpr int WIDTH = 640;
|
||||
constexpr int HEIGHT = 480;
|
||||
} // namespace Game
|
||||
|
||||
// Zones del joc (SDL_FRect amb càlculs automàtics basat en percentatges)
|
||||
// Zones del juego (SDL_FRect con cálculos automàtics basat en percentatges)
|
||||
namespace Zones {
|
||||
// --- CONFIGURACIÓ DE PORCENTATGES ---
|
||||
// Totes les zones definides com a percentatges de Game::WIDTH (640) i Game::HEIGHT (480)
|
||||
// Todas las zones definides como a percentatges de Game::WIDTH (640) i Game::HEIGHT (480)
|
||||
|
||||
// Percentatges d'alçada (divisió vertical)
|
||||
// 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 per a PLAYAREA (dins de MAIN_PLAYAREA)
|
||||
// Padding horizontal para PLAYAREA (dins de MAIN_PLAYAREA)
|
||||
constexpr float PLAYAREA_PADDING_HORIZONTAL_PERCENT = 0.015F; // 5% a cada costat
|
||||
|
||||
// --- CÀLCULS AUTOMÀTICS DE PÍXELS ---
|
||||
// Càlculs automàtics a partir dels percentatges
|
||||
// Cálculos automàtics a partir dels percentatges
|
||||
|
||||
// Alçades
|
||||
constexpr float SCOREBOARD_TOP_H = Game::HEIGHT * SCOREBOARD_TOP_HEIGHT_PERCENT;
|
||||
@@ -56,7 +56,7 @@ constexpr float PLAYAREA_PADDING_H = Game::WIDTH * PLAYAREA_PADDING_HORIZONTAL_P
|
||||
|
||||
// --- ZONES FINALS (SDL_FRect) ---
|
||||
|
||||
// Marcador superior (reservat per a futur ús)
|
||||
// Marcador superior (reservat para futur ús)
|
||||
// Ocupa: 10% superior (0-48px)
|
||||
constexpr SDL_FRect SCOREBOARD_TOP = {
|
||||
0.0F, // x = 0.0
|
||||
@@ -65,7 +65,7 @@ constexpr SDL_FRect SCOREBOARD_TOP = {
|
||||
SCOREBOARD_TOP_H // h = 48.0
|
||||
};
|
||||
|
||||
// Àrea de joc principal (contenidor del 80% central, sense padding)
|
||||
// Àrea de juego principal (contenidor del 80% central, sin padding)
|
||||
// Ocupa: 10-90% (48-432px), ample complet
|
||||
constexpr SDL_FRect MAIN_PLAYAREA = {
|
||||
0.0F, // x = 0.0
|
||||
@@ -74,9 +74,9 @@ constexpr SDL_FRect MAIN_PLAYAREA = {
|
||||
MAIN_PLAYAREA_H // h = 384.0
|
||||
};
|
||||
|
||||
// Zona de joc real (amb padding horizontal del 5%)
|
||||
// Ocupa: dins de MAIN_PLAYAREA, amb marges laterals
|
||||
// S'utilitza per a límits del joc, col·lisions, spawn
|
||||
// Zona de juego real (con padding horizontal del 5%)
|
||||
// Ocupa: dins de MAIN_PLAYAREA, con marges laterals
|
||||
// S'utilitza para límits del juego, colisiones, spawn
|
||||
constexpr SDL_FRect PLAYAREA = {
|
||||
PLAYAREA_PADDING_H, // x = 32.0
|
||||
MAIN_PLAYAREA_Y, // y = 48.0 (igual que MAIN_PLAYAREA)
|
||||
@@ -93,7 +93,7 @@ constexpr SDL_FRect SCOREBOARD = {
|
||||
SCOREBOARD_BOTTOM_H // h = 48.0
|
||||
};
|
||||
|
||||
// Padding horizontal del marcador (per alinear zones esquerra/dreta amb PLAYAREA)
|
||||
// Padding horizontal del marcador (per alinear zones izquierda/derecha con PLAYAREA)
|
||||
constexpr float SCOREBOARD_PADDING_H = 0.0F; // Game::WIDTH * 0.015f;
|
||||
} // namespace Zones
|
||||
|
||||
@@ -211,11 +211,11 @@ constexpr float VELOCITY_SCALE = 20.0F; // factor conversión frame→tiempo
|
||||
|
||||
// Explosions (debris physics)
|
||||
namespace Debris {
|
||||
constexpr float VELOCITAT_BASE = 80.0F; // Velocitat inicial (px/s)
|
||||
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ó mínima (rad/s ~5.7°/s)
|
||||
constexpr float ROTACIO_MAX = 0.3F; // Rotació màxima (rad/s ~17.2°/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)
|
||||
@@ -225,7 +225,7 @@ 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 cap for trajectory inheritance
|
||||
// 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)
|
||||
@@ -261,21 +261,21 @@ constexpr uint8_t BACKGROUND_MAX_G = 15;
|
||||
constexpr uint8_t BACKGROUND_MAX_B = 0;
|
||||
} // namespace Color
|
||||
|
||||
// Brillantor (control de intensitat per cada type d'entitat)
|
||||
// Brillantor (control de intensitat per cada type de entidad)
|
||||
namespace Brightness {
|
||||
// Brillantor estàtica per entitats de joc (0.0-1.0)
|
||||
// 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 distància al centre
|
||||
// distancia_centre: 0.0 (centre) → 1.0 (vora pantalla)
|
||||
// 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 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 opcions de render)
|
||||
// Renderització (V-Sync i altres opciones de render)
|
||||
namespace Rendering {
|
||||
constexpr int VSYNC_DEFAULT = 1; // 0=disabled, 1=enabled
|
||||
} // namespace Rendering
|
||||
@@ -327,7 +327,7 @@ constexpr SDL_Keycode SHOOT = SDLK_LSHIFT;
|
||||
} // namespace P2
|
||||
} // namespace Controls
|
||||
|
||||
// Enemy type configuration (type d'enemics)
|
||||
// Enemy type configuration (type de enemigos)
|
||||
namespace Enemies {
|
||||
// Pentagon (esquivador - zigzag evasion)
|
||||
namespace Pentagon {
|
||||
@@ -339,15 +339,15 @@ constexpr float DROTACIO_MAX = 3.75F; // Max visual rotation (rad/s) [+50%]
|
||||
constexpr const char* SHAPE_FILE = "enemy_pentagon.shp";
|
||||
} // namespace Pentagon
|
||||
|
||||
// Quadrat (perseguidor - tracks player)
|
||||
namespace Quadrat {
|
||||
// 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 Quadrat
|
||||
} // namespace Cuadrado
|
||||
|
||||
// Molinillo (agressiu - fast straight lines, proximity spin-up)
|
||||
namespace Molinillo {
|
||||
@@ -395,34 +395,34 @@ constexpr float INVULNERABILITY_SCALE_START = 0.0F; // Invisible
|
||||
constexpr float INVULNERABILITY_SCALE_END = 1.0F; // Full size
|
||||
} // namespace Spawn
|
||||
|
||||
// Scoring system (puntuació per type d'enemy)
|
||||
// Scoring system (puntuación per type de enemy)
|
||||
namespace Scoring {
|
||||
constexpr int PENTAGON_SCORE = 100; // Pentàgon (esquivador, 35 px/s)
|
||||
constexpr int QUADRAT_SCORE = 150; // Quadrat (perseguidor, 40 px/s)
|
||||
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 (naus 3D flotants a l'escena de títol)
|
||||
// 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 les naus
|
||||
// 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 (distancia radial desde centro en coordenadas polares)
|
||||
constexpr float CLOCK_RADIUS = 150.0F; // Distància des del centre
|
||||
// 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 coordenades de pantalla: 0° = dreta, 90° = baix, 180° = esquerra, 270° = dalt
|
||||
// En coordenades 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)
|
||||
|
||||
@@ -436,13 +436,13 @@ constexpr float ENTRY_OFFSET_MARGIN = 227.5F; // Para offset total de ~340px (a
|
||||
// VALORS DERIVATS (calculats automàticament - NO modificar)
|
||||
// ============================================================
|
||||
|
||||
// Centre de la pantalla (point de referència)
|
||||
// Centro de la pantalla (point de referència)
|
||||
constexpr float CENTER_X = Game::WIDTH / 2.0F; // 320.0f
|
||||
constexpr float CENTER_Y = Game::HEIGHT / 2.0F; // 240.0f
|
||||
|
||||
// Posicions target (calculades dinàmicament des dels paràmetres base)
|
||||
// Nota: std::cos/sin no són constexpr en C++20, però funcionen en runtime
|
||||
// Les funcions inline són optimitzades pel compilador (zero overhead)
|
||||
// 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 float P1_TARGET_X() {
|
||||
return CENTER_X + (CLOCK_RADIUS * std::cos(CLOCK_8_ANGLE));
|
||||
}
|
||||
@@ -456,15 +456,15 @@ inline float P2_TARGET_Y() {
|
||||
return CENTER_Y + ((Game::HEIGHT / 2.0F) * TARGET_Y_RATIO);
|
||||
}
|
||||
|
||||
// Escales d'animació (relatives a SHIP_BASE_SCALE)
|
||||
constexpr float ENTRY_SCALE_START = 1.5F * SHIP_BASE_SCALE; // Entrada: 50% més gran
|
||||
constexpr float FLOATING_SCALE = 1.0F * SHIP_BASE_SCALE; // Flotant: scale base
|
||||
// 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 d'entrada (ajustat automàticament a l'scale)
|
||||
// Fórmula: (radi màxim de la ship * scale d'entrada) + marge
|
||||
// Offset de entrada (ajustat automàticament a l'scale)
|
||||
// Fórmula: (radi màxim de la ship * scale de entrada) + marge
|
||||
constexpr float ENTRY_OFFSET = (SHIP_MAX_RADIUS * ENTRY_SCALE_START) + ENTRY_OFFSET_MARGIN;
|
||||
|
||||
// Vec2 de fuga (centre per a l'animació de sortida)
|
||||
// Vec2 de fuga (centro para l'animación de salida)
|
||||
constexpr float VANISHING_POINT_X = CENTER_X; // 320.0f
|
||||
constexpr float VANISHING_POINT_Y = CENTER_Y; // 240.0f
|
||||
|
||||
@@ -472,11 +472,11 @@ constexpr float VANISHING_POINT_Y = CENTER_Y; // 240.0f
|
||||
// ANIMACIONS (durades, oscil·lacions, delays)
|
||||
// ============================================================
|
||||
|
||||
// Durades d'animació
|
||||
// Durades de animación
|
||||
constexpr float ENTRY_DURATION = 2.0F; // Entrada (segons)
|
||||
constexpr float EXIT_DURATION = 1.0F; // Sortida (segons)
|
||||
constexpr float EXIT_DURATION = 1.0F; // Salida (segons)
|
||||
|
||||
// Flotació (oscil·lació reduïda i diferenciada per ship)
|
||||
// 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)
|
||||
|
||||
@@ -485,21 +485,21 @@ 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 d'entrada (per a entrada escalonada)
|
||||
// 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 després
|
||||
constexpr float P2_ENTRY_DELAY = 0.5F; // P2 entra 0.5s después
|
||||
|
||||
// Delay global abans d'iniciar l'animació d'entrada al state MAIN
|
||||
constexpr float ENTRANCE_DELAY = 5.0F; // Temps d'espera abans que les naus entrin
|
||||
// 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 per a cada ship (variació sutil ±12%)
|
||||
// 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)
|
||||
// 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
|
||||
@@ -508,21 +508,21 @@ constexpr float COPYRIGHT1_POS = 0.90F; // Primera línia copyright
|
||||
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 d'scale
|
||||
// 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
|
||||
|
||||
// Espaiat entre caràcters (usat per VectorText)
|
||||
// Espaiat entre caràcters (usado per VectorText)
|
||||
constexpr float TEXT_SPACING = 2.0F;
|
||||
} // namespace Layout
|
||||
} // namespace Title
|
||||
|
||||
// Floating score numbers (números flotants de puntuació)
|
||||
// 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; // Velocitat vertical (px/s, negatiu = amunt)
|
||||
constexpr float VELOCITY_X = 0.0F; // Velocitat horizontal (px/s)
|
||||
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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// entitat.hpp - Classe base abstracta per a totes les entitats del joc
|
||||
// © 2025 Orni Attack - Arquitectura d'entitats
|
||||
// entity.hpp - Clase base abstracta para todas las entidades del juego
|
||||
// © 2025 Orni Attack - Arquitectura de entidades
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -22,25 +22,25 @@ class Entity {
|
||||
virtual void draw() const = 0;
|
||||
[[nodiscard]] virtual bool isActive() const = 0;
|
||||
|
||||
// Interfície de col·lisió (override opcional)
|
||||
// Interfície de colisión (override opcional)
|
||||
[[nodiscard]] virtual float getCollisionRadius() const { return 0.0F; }
|
||||
[[nodiscard]] virtual bool isCollidable() const { return false; }
|
||||
|
||||
// Getters comuns (inline, sense overhead)
|
||||
// Getters comuns (inline, sin overhead)
|
||||
[[nodiscard]] const Vec2& getCenter() const { return center_; }
|
||||
[[nodiscard]] float getAngle() const { return angle_; }
|
||||
[[nodiscard]] float getBrightness() const { return brightness_; }
|
||||
[[nodiscard]] const std::shared_ptr<Graphics::Shape>& getShape() const { return shape_; }
|
||||
|
||||
protected:
|
||||
// Estat comú (accés directe, sense overhead)
|
||||
// Estat comú (accés directe, sin overhead)
|
||||
SDL_Renderer* renderer_;
|
||||
std::shared_ptr<Graphics::Shape> shape_;
|
||||
Vec2 center_;
|
||||
float angle_{0.0F};
|
||||
float brightness_{1.0F};
|
||||
|
||||
// Constructor protegit (classe abstracta)
|
||||
// Constructor protegit (clase abstracta)
|
||||
Entity(SDL_Renderer* renderer = nullptr)
|
||||
: renderer_(renderer),
|
||||
center_({.x = 0.0F, .y = 0.0F}) {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// shape.cpp - Implementació del sistema de formes vectorials
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "core/graphics/shape.hpp"
|
||||
|
||||
@@ -18,14 +18,14 @@ Shape::Shape(const std::string& filepath)
|
||||
}
|
||||
|
||||
bool Shape::load(const std::string& filepath) {
|
||||
// Llegir fitxer
|
||||
// Llegir file
|
||||
std::ifstream file(filepath);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "[Shape] Error: no es pot obrir " << filepath << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
// Llegir tot el contingut
|
||||
// Llegir todo el contingut
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
std::string contingut = buffer.str();
|
||||
@@ -65,7 +65,7 @@ bool Shape::parseFile(const std::string& contingut) {
|
||||
if (points.size() >= 2) {
|
||||
primitives_.push_back({PrimitiveType::POLYLINE, points});
|
||||
} else {
|
||||
std::cerr << "[Shape] Warning: polyline amb menys de 2 points ignorada"
|
||||
std::cerr << "[Shape] Warning: polyline con menys de 2 points ignorada"
|
||||
<< '\n';
|
||||
}
|
||||
} else if (starts_with(line, "line:")) {
|
||||
@@ -81,7 +81,7 @@ bool Shape::parseFile(const std::string& contingut) {
|
||||
}
|
||||
|
||||
if (primitives_.empty()) {
|
||||
std::cerr << "[Shape] Error: cap primitiva carregada" << '\n';
|
||||
std::cerr << "[Shape] Error: sin primitiva carregada" << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ void Shape::parse_center(const std::string& value) {
|
||||
center_.x = std::stof(trim(val.substr(0, comma)));
|
||||
center_.y = std::stof(trim(val.substr(comma + 1)));
|
||||
} catch (...) {
|
||||
std::cerr << "[Shape] Warning: centre invàlid, usant (0,0)" << '\n';
|
||||
std::cerr << "[Shape] Warning: centro invàlid, usant (0,0)" << '\n';
|
||||
center_ = {.x = 0.0F, .y = 0.0F};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// shape.hpp - Sistema de formes vectorials
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
// Tipus de primitiva dins d'una shape
|
||||
// Tipo de primitiva dins de una shape
|
||||
enum class PrimitiveType {
|
||||
POLYLINE, // Seqüència de points connectats
|
||||
POLYLINE, // Secuencia de points connectats
|
||||
LINE // Línia individual (2 points)
|
||||
};
|
||||
|
||||
@@ -22,17 +22,17 @@ struct ShapePrimitive {
|
||||
std::vector<Vec2> points; // 2+ points per polyline, exactament 2 per line
|
||||
};
|
||||
|
||||
// Classe Shape - representa una shape vectorial carregada des de .shp
|
||||
// Clase Shape - representa una shape vectorial carregada desde .shp
|
||||
class Shape {
|
||||
public:
|
||||
// Constructors
|
||||
Shape() = default;
|
||||
explicit Shape(const std::string& filepath);
|
||||
|
||||
// Carregar shape des de fitxer .shp
|
||||
// Carregar shape desde file .shp
|
||||
bool load(const std::string& filepath);
|
||||
|
||||
// Parsejar shape des de buffer de memòria (per al sistema de recursos)
|
||||
// Parsejar shape desde buffer de memòria (per al sistema de recursos)
|
||||
bool parseFile(const std::string& contingut);
|
||||
|
||||
// Getters
|
||||
@@ -49,7 +49,7 @@ class Shape {
|
||||
|
||||
private:
|
||||
std::vector<ShapePrimitive> primitives_;
|
||||
Vec2 center_; // Centre/origen de la shape
|
||||
Vec2 center_; // Centro/origin de la shape
|
||||
float escala_defecte_; // Escala per defecte (normalment 1.0)
|
||||
std::string nom_; // Nom de la shape (per depuració)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// shape_loader.cpp - Implementació del carregador amb caché
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// shape_loader.cpp - Implementació del carregador con caché
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "core/graphics/shape_loader.hpp"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
// Inicialització de variables estàtiques
|
||||
// Inicialización de variables estàtiques
|
||||
std::unordered_map<std::string, std::shared_ptr<Shape>> ShapeLoader::cache_;
|
||||
std::string ShapeLoader::base_path_ = "data/shapes/";
|
||||
|
||||
@@ -69,17 +69,17 @@ void ShapeLoader::clear_cache() {
|
||||
size_t ShapeLoader::get_cache_size() { return cache_.size(); }
|
||||
|
||||
std::string ShapeLoader::resolve_path(const std::string& filename) {
|
||||
// Si és un path absolut (comença amb '/'), usar-lo directament
|
||||
// Si es un path absolut (comença con '/'), usar-lo directament
|
||||
if (!filename.empty() && filename[0] == '/') {
|
||||
return filename;
|
||||
}
|
||||
|
||||
// Si ja conté el prefix base_path, usar-lo directament
|
||||
// Si ya conté el prefix base_path, usar-lo directament
|
||||
if (filename.starts_with(base_path_)) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
// Altrament, afegir base_path (ara suporta subdirectoris)
|
||||
// Altrament, añadir base_path (ara suporta subdirectoris)
|
||||
return base_path_ + filename;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// shape_loader.hpp - Carregador estàtic de formes amb caché
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// shape_loader.hpp - Carregador estàtic de formes con caché
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
// Carregador estàtic de formes amb caché
|
||||
// Carregador estàtic de formes con caché
|
||||
class ShapeLoader {
|
||||
public:
|
||||
// No instanciable (tot estàtic)
|
||||
ShapeLoader() = delete;
|
||||
|
||||
// Carregar shape des de fitxer (amb caché)
|
||||
// Carregar shape desde file (con caché)
|
||||
// Retorna punter compartit (nullptr si error)
|
||||
// Exemple: load("ship.shp") → busca a "data/shapes/ship.shp"
|
||||
static std::shared_ptr<Shape> load(const std::string& filename);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// starfield.cpp - Implementació del sistema d'estrelles de fons
|
||||
// starfield.cpp - Implementació del sistema de estrelles de fons
|
||||
// © 2025 Orni Attack
|
||||
|
||||
#include "core/graphics/starfield.hpp"
|
||||
@@ -22,7 +22,7 @@ Starfield::Starfield(SDL_Renderer* renderer,
|
||||
punt_fuga_(punt_fuga),
|
||||
area_(area),
|
||||
densitat_(densitat) {
|
||||
// Carregar shape d'estrella amb ShapeLoader
|
||||
// Carregar shape de estrella con ShapeLoader
|
||||
shape_estrella_ = ShapeLoader::load("star.shp");
|
||||
|
||||
if (!shape_estrella_ || !shape_estrella_->isValid()) {
|
||||
@@ -30,22 +30,22 @@ Starfield::Starfield(SDL_Renderer* renderer,
|
||||
return;
|
||||
}
|
||||
|
||||
// Configurar 3 capes amb diferents velocitats i escales
|
||||
// Capa 0: Fons llunyà (lenta, petita)
|
||||
// Configurar 3 capes con diferents velocitats i escales
|
||||
// Capa 0: Fons llunyà (lenta, pequeña)
|
||||
capes_.push_back({20.0F, 0.3F, 0.8F, densitat / 3});
|
||||
|
||||
// Capa 1: Profunditat mitjana
|
||||
capes_.push_back({40.0F, 0.5F, 1.2F, densitat / 3});
|
||||
|
||||
// Capa 2: Primer pla (ràpida, gran)
|
||||
// Capa 2: Primer pla (ràpida, grande)
|
||||
capes_.push_back({80.0F, 0.8F, 2.0F, densitat / 3});
|
||||
|
||||
// Calcular radi màxim (distància del centre al racó més llunyà)
|
||||
// Calcular radi màxim (distancia del centro al racó més llunyà)
|
||||
float dx = std::max(punt_fuga_.x, area_.w - punt_fuga_.x);
|
||||
float dy = std::max(punt_fuga_.y, area_.h - punt_fuga_.y);
|
||||
radi_max_ = std::sqrt((dx * dx) + (dy * dy));
|
||||
|
||||
// Inicialitzar estrelles amb posicions distribuïdes (pre-omplir pantalla)
|
||||
// Inicialitzar estrelles con posicions distribuïdes (pre-omplir pantalla)
|
||||
for (int capa_idx = 0; capa_idx < 3; capa_idx++) {
|
||||
int num = capes_[capa_idx].num_estrelles;
|
||||
for (int i = 0; i < num; i++) {
|
||||
@@ -55,10 +55,10 @@ Starfield::Starfield(SDL_Renderer* renderer,
|
||||
// Angle aleatori
|
||||
estrella.angle = (static_cast<float>(rand()) / RAND_MAX) * 2.0F * Defaults::Math::PI;
|
||||
|
||||
// Distància aleatòria (0.0 a 1.0) per omplir tota la pantalla
|
||||
// Distancia aleatòria (0.0 a 1.0) per omplir toda la pantalla
|
||||
estrella.distancia_centre = static_cast<float>(rand()) / RAND_MAX;
|
||||
|
||||
// Calcular posició des de la distància
|
||||
// Calcular posición desde la distancia
|
||||
float radi = estrella.distancia_centre * radi_max_;
|
||||
estrella.position.x = punt_fuga_.x + (radi * std::cos(estrella.angle));
|
||||
estrella.position.y = punt_fuga_.y + (radi * std::sin(estrella.angle));
|
||||
@@ -68,21 +68,21 @@ Starfield::Starfield(SDL_Renderer* renderer,
|
||||
}
|
||||
}
|
||||
|
||||
// Inicialitzar una estrella (nova o regenerada)
|
||||
// Inicialitzar una estrella (nueva o regenerada)
|
||||
void Starfield::inicialitzar_estrella(Estrella& estrella) const {
|
||||
// Angle aleatori des del point de fuga cap a fora
|
||||
// Angle aleatori des del point de fuga hacia fuera
|
||||
estrella.angle = (static_cast<float>(rand()) / RAND_MAX) * 2.0F * Defaults::Math::PI;
|
||||
|
||||
// Distància inicial petita (5% del radi màxim) - neix prop del centre
|
||||
// Distancia inicial pequeña (5% del radi màxim) - neix prop del centro
|
||||
estrella.distancia_centre = 0.05F;
|
||||
|
||||
// Posició inicial: molt prop del point de fuga
|
||||
// Posición inicial: mucho prop del point de fuga
|
||||
float radi = estrella.distancia_centre * radi_max_;
|
||||
estrella.position.x = punt_fuga_.x + (radi * std::cos(estrella.angle));
|
||||
estrella.position.y = punt_fuga_.y + (radi * std::sin(estrella.angle));
|
||||
}
|
||||
|
||||
// Verificar si una estrella està fora de l'àrea
|
||||
// Verificar si una estrella está fuera de l'àrea
|
||||
bool Starfield::fora_area(const Estrella& estrella) const {
|
||||
return (estrella.position.x < area_.x ||
|
||||
estrella.position.x > area_.x + area_.w ||
|
||||
@@ -90,20 +90,20 @@ bool Starfield::fora_area(const Estrella& estrella) const {
|
||||
estrella.position.y > area_.y + area_.h);
|
||||
}
|
||||
|
||||
// Calcular scale dinàmica segons distància del centre
|
||||
// Calcular scale dinàmica segons distancia del centro
|
||||
float Starfield::calcular_escala(const Estrella& estrella) const {
|
||||
const CapaConfig& capa = capes_[estrella.capa];
|
||||
|
||||
// Interpolació lineal basada en distància del centre
|
||||
// distancia_centre: 0.0 (centre) → 1.0 (vora)
|
||||
// Interpolació lineal basada en distancia del centro
|
||||
// distancia_centre: 0.0 (centro) → 1.0 (vora)
|
||||
return capa.escala_min +
|
||||
((capa.escala_max - capa.escala_min) * estrella.distancia_centre);
|
||||
}
|
||||
|
||||
// Calcular brightness dinàmica segons distància del centre
|
||||
// Calcular brightness dinàmica segons distancia del centro
|
||||
float Starfield::calcular_brightness(const Estrella& estrella) const {
|
||||
// Interpolació lineal: estrelles properes (vora) més brillants
|
||||
// distancia_centre: 0.0 (centre, llunyanes) → 1.0 (vora, properes)
|
||||
// distancia_centre: 0.0 (centro, llunyanes) → 1.0 (vora, properes)
|
||||
float brightness_base = Defaults::Brightness::STARFIELD_MIN +
|
||||
((Defaults::Brightness::STARFIELD_MAX - Defaults::Brightness::STARFIELD_MIN) *
|
||||
estrella.distancia_centre);
|
||||
@@ -112,13 +112,13 @@ float Starfield::calcular_brightness(const Estrella& estrella) const {
|
||||
return std::min(1.0F, brightness_base * multiplicador_brightness_);
|
||||
}
|
||||
|
||||
// Actualitzar posicions de les estrelles
|
||||
// Actualitzar posicions de las estrelles
|
||||
void Starfield::update(float delta_time) {
|
||||
for (auto& estrella : estrelles_) {
|
||||
// Obtenir configuració de la capa
|
||||
// Obtenir configuración de la capa
|
||||
const CapaConfig& capa = capes_[estrella.capa];
|
||||
|
||||
// Moure cap a fora des del centre
|
||||
// Moure hacia fuera des del centro
|
||||
float velocity = capa.velocitat_base;
|
||||
float dx = velocity * std::cos(estrella.angle) * delta_time;
|
||||
float dy = velocity * std::sin(estrella.angle) * delta_time;
|
||||
@@ -126,7 +126,7 @@ void Starfield::update(float delta_time) {
|
||||
estrella.position.x += dx;
|
||||
estrella.position.y += dy;
|
||||
|
||||
// Actualitzar distància del centre
|
||||
// Actualitzar distancia del centro
|
||||
float dx_centre = estrella.position.x - punt_fuga_.x;
|
||||
float dy_centre = estrella.position.y - punt_fuga_.y;
|
||||
float dist_px = std::sqrt((dx_centre * dx_centre) + (dy_centre * dy_centre));
|
||||
@@ -144,7 +144,7 @@ void Starfield::set_brightness(float multiplier) {
|
||||
multiplicador_brightness_ = std::max(0.0F, multiplier); // Evitar valors negatius
|
||||
}
|
||||
|
||||
// Dibuixar totes les estrelles
|
||||
// Dibuixar todas las estrelles
|
||||
void Starfield::draw() {
|
||||
if (!shape_estrella_->isValid()) {
|
||||
return;
|
||||
@@ -155,14 +155,14 @@ void Starfield::draw() {
|
||||
float scale = calcular_escala(estrella);
|
||||
float brightness = calcular_brightness(estrella);
|
||||
|
||||
// Renderitzar estrella sense rotació
|
||||
// Renderizar estrella sin rotación
|
||||
Rendering::render_shape(
|
||||
renderer_,
|
||||
shape_estrella_,
|
||||
estrella.position,
|
||||
0.0F, // angle (les estrelles no giren)
|
||||
0.0F, // angle (las estrelles no giren)
|
||||
scale, // scale dinàmica
|
||||
1.0F, // progress (sempre visible)
|
||||
1.0F, // progress (siempre visible)
|
||||
brightness // brightness dinàmica
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// starfield.hpp - Sistema d'estrelles de fons amb efecte de profunditat
|
||||
// starfield.hpp - Sistema de estrelles de fons con efecte de profunditat
|
||||
// © 2025 Orni Attack
|
||||
|
||||
#pragma once
|
||||
@@ -13,69 +13,69 @@
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
// Configuració per cada capa de profunditat
|
||||
// Configuración per cada capa de profunditat
|
||||
struct CapaConfig {
|
||||
float velocitat_base; // Velocitat base d'aquesta capa (px/s)
|
||||
float escala_min; // Escala mínima prop del centre
|
||||
float velocitat_base; // Velocidad base de esta capa (px/s)
|
||||
float escala_min; // Escala mínima prop del centro
|
||||
float escala_max; // Escala màxima al límit de pantalla
|
||||
int num_estrelles; // Nombre d'estrelles en aquesta capa
|
||||
int num_estrelles; // Nombre de estrelles en esta capa
|
||||
};
|
||||
|
||||
// Classe Starfield - camp d'estrelles animat amb efecte de profunditat
|
||||
// Clase Starfield - camp de estrelles animat con efecte de profunditat
|
||||
class Starfield {
|
||||
public:
|
||||
// Constructor
|
||||
// - renderer: SDL renderer
|
||||
// - punt_fuga: point d'origen/fuga des d'on surten les estrelles
|
||||
// - area: rectangle on actuen les estrelles (SDL_FRect)
|
||||
// - densitat: nombre total d'estrelles (es divideix entre capes)
|
||||
// - punt_fuga: point de origin/fuga des de on surten las estrelles
|
||||
// - area: rectangle on actuen las estrelles (SDL_FRect)
|
||||
// - densitat: nombre total de estrelles (es divideix entre capes)
|
||||
Starfield(SDL_Renderer* renderer,
|
||||
const Vec2& punt_fuga,
|
||||
const SDL_FRect& area,
|
||||
int densitat = 150);
|
||||
|
||||
// Actualitzar posicions de les estrelles
|
||||
// Actualitzar posicions de las estrelles
|
||||
void update(float delta_time);
|
||||
|
||||
// Dibuixar totes les estrelles
|
||||
// Dibuixar todas las estrelles
|
||||
void draw();
|
||||
|
||||
// Setters per ajustar paràmetres en time real
|
||||
// Setters per ajustar parámetros en time real
|
||||
void set_punt_fuga(const Vec2& point) { punt_fuga_ = point; }
|
||||
void set_brightness(float multiplier);
|
||||
|
||||
private:
|
||||
// Estructura interna per cada estrella
|
||||
struct Estrella {
|
||||
Vec2 position; // Posició actual
|
||||
float angle; // Angle de moviment (radians)
|
||||
float distancia_centre; // Distància normalitzada del centre (0.0-1.0)
|
||||
Vec2 position; // Posición actual
|
||||
float angle; // Angle de movement (radians)
|
||||
float distancia_centre; // Distancia normalitzada del centro (0.0-1.0)
|
||||
int capa; // Índex de capa (0=lluny, 1=mitjà, 2=prop)
|
||||
};
|
||||
|
||||
// Inicialitzar una estrella (nova o regenerada)
|
||||
// Inicialitzar una estrella (nueva o regenerada)
|
||||
void inicialitzar_estrella(Estrella& estrella) const;
|
||||
|
||||
// Verificar si una estrella està fora de l'àrea
|
||||
// Verificar si una estrella está fuera de l'àrea
|
||||
[[nodiscard]] bool fora_area(const Estrella& estrella) const;
|
||||
|
||||
// Calcular scale dinàmica segons distància del centre
|
||||
// Calcular scale dinàmica segons distancia del centro
|
||||
[[nodiscard]] float calcular_escala(const Estrella& estrella) const;
|
||||
|
||||
// Calcular brightness dinàmica segons distància del centre
|
||||
// Calcular brightness dinàmica segons distancia del centro
|
||||
[[nodiscard]] float calcular_brightness(const Estrella& estrella) const;
|
||||
|
||||
// Dades
|
||||
std::vector<Estrella> estrelles_;
|
||||
std::vector<CapaConfig> capes_; // Configuració de les 3 capes
|
||||
std::vector<CapaConfig> capes_; // Configuración de las 3 capes
|
||||
std::shared_ptr<Shape> shape_estrella_;
|
||||
SDL_Renderer* renderer_;
|
||||
|
||||
// Configuració
|
||||
Vec2 punt_fuga_; // Vec2 d'origen de les estrelles
|
||||
// Configuración
|
||||
Vec2 punt_fuga_; // Vec2 de origin de las estrelles
|
||||
SDL_FRect area_; // Àrea activa
|
||||
float radi_max_; // Distància màxima del centre al límit de pantalla
|
||||
int densitat_; // Nombre total d'estrelles
|
||||
float radi_max_; // Distancia màxima del centro al límit de pantalla
|
||||
int densitat_; // Nombre total de estrelles
|
||||
float multiplicador_brightness_{1.0F}; // Multiplicador de brightness (1.0 = default)
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// vector_text.cpp - Implementació del sistema de text vectorial
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
// Test pre-commit hook
|
||||
|
||||
#include "core/graphics/vector_text.hpp"
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
// Constants per a mides base dels caràcters
|
||||
// Constants para mides base dels caràcters
|
||||
constexpr float char_width = 20.0F; // Amplada base del caràcter
|
||||
constexpr float char_height = 40.0F; // Altura base del caràcter
|
||||
|
||||
@@ -63,7 +63,7 @@ void VectorText::load_charset() {
|
||||
}
|
||||
|
||||
// Cargar símbolo de copyright (©) - UTF-8 U+00A9
|
||||
// Usem el segon byte (0xA9) com a key interna
|
||||
// Usem el segon byte (0xA9) como a key interna
|
||||
{
|
||||
char c = '\xA9'; // 169 decimal
|
||||
std::string filename = "font/char_copyright.shp";
|
||||
@@ -82,7 +82,7 @@ void VectorText::load_charset() {
|
||||
}
|
||||
|
||||
std::string VectorText::get_shape_filename(char c) const {
|
||||
// Mapeo carácter → nombre de archivo (amb prefix "font/")
|
||||
// Mapeo carácter → nombre de archivo (con prefix "font/")
|
||||
switch (c) {
|
||||
case '0':
|
||||
case '1':
|
||||
@@ -168,7 +168,7 @@ std::string VectorText::get_shape_filename(char c) const {
|
||||
case '?':
|
||||
return "font/char_question.shp";
|
||||
case ' ':
|
||||
return ""; // Espai es maneja sense load shape
|
||||
return ""; // Espai es maneja sin load shape
|
||||
|
||||
case '\xA9': // Copyright symbol (©) - UTF-8 U+00A9
|
||||
return "font/char_copyright.shp";
|
||||
@@ -207,7 +207,7 @@ void VectorText::render(const std::string& text, const Vec2& position, float sca
|
||||
// Detectar copyright UTF-8 (0xC2 0xA9)
|
||||
if (c == 0xC2 && i + 1 < text.length() &&
|
||||
static_cast<unsigned char>(text[i + 1]) == 0xA9) {
|
||||
c = 0xA9; // Usar segon byte com a key
|
||||
c = 0xA9; // Usar segon byte como a key
|
||||
i++; // Saltar el següent byte
|
||||
}
|
||||
|
||||
@@ -242,13 +242,13 @@ void VectorText::renderCentered(const std::string& text, const Vec2& centre_punt
|
||||
float text_width = get_text_width(text, scale, spacing);
|
||||
float text_height = get_text_height(scale);
|
||||
|
||||
// Calcular posició de l'esquina superior esquerra
|
||||
// restant la meitat de les dimensions del point central
|
||||
// Calcular posición de l'esquina superior izquierda
|
||||
// restant la meitat de las dimensions del point central
|
||||
Vec2 posicio_esquerra = {
|
||||
.x = centre_punt.x - (text_width / 2.0F),
|
||||
.y = centre_punt.y - (text_height / 2.0F)};
|
||||
|
||||
// Delegar al mètode render() existent
|
||||
// Delegar al método render() existent
|
||||
render(text, posicio_esquerra, scale, spacing, brightness);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// vector_text.hpp - Sistema de texto vectorial con display de 7-segmentos
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ bool cursor_visible = false; // Estado del cursor (inicia ocult)
|
||||
// SDLManager controla esto mediante llamadas a setForceHidden().
|
||||
bool force_hidden = false;
|
||||
|
||||
// Temps d'inicialització per ignorar esdeveniments fantasma de SDL
|
||||
// Temps de inicialización per ignorar esdeveniments fantasma de SDL
|
||||
Uint32 initialization_time = 0;
|
||||
constexpr Uint32 IGNORE_MOTION_DURATION = 1000; // Ignorar primers 1000ms
|
||||
|
||||
@@ -24,7 +24,7 @@ void forceHide() {
|
||||
cursor_visible = false;
|
||||
last_mouse_move_time = 0;
|
||||
initialization_time = SDL_GetTicks(); // Marcar time per ignorar esdeveniments inicials
|
||||
std::cout << "[Mouse::forceHide] Ignorant moviments durant " << IGNORE_MOTION_DURATION << "ms" << '\n';
|
||||
std::cout << "[Mouse::forceHide] Ignorant moviments durante " << IGNORE_MOTION_DURATION << "ms" << '\n';
|
||||
}
|
||||
|
||||
void setForceHidden(bool force) {
|
||||
@@ -56,16 +56,16 @@ void handleEvent(const SDL_Event& event) {
|
||||
if (event.type == SDL_EVENT_MOUSE_MOTION) {
|
||||
Uint32 current_time = SDL_GetTicks();
|
||||
|
||||
// Ignorar esdeveniments fantasma de SDL durant el període inicial
|
||||
// Ignorar esdeveniments fantasma de SDL durante el període inicial
|
||||
if (initialization_time > 0 && (current_time - initialization_time < IGNORE_MOTION_DURATION)) {
|
||||
std::cout << "[Mouse::handleEvent] Ignorant moviment fantasma de SDL. time=" << current_time
|
||||
<< " (inicialització fa " << (current_time - initialization_time) << "ms)" << '\n';
|
||||
std::cout << "[Mouse::handleEvent] Ignorant movement fantasma de SDL. time=" << current_time
|
||||
<< " (inicialización hace " << (current_time - initialization_time) << "ms)" << '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
last_mouse_move_time = current_time;
|
||||
if (!cursor_visible) {
|
||||
std::cout << "[Mouse::handleEvent] Mostrant cursor per moviment REAL. time=" << last_mouse_move_time << '\n';
|
||||
std::cout << "[Mouse::handleEvent] Mostrant cursor per movement REAL. time=" << last_mouse_move_time << '\n';
|
||||
SDL_ShowCursor();
|
||||
cursor_visible = true;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// easing.hpp - Funcions d'interpolació i easing
|
||||
// easing.hpp - Funciones de interpolació i easing
|
||||
// © 2025 Orni Attack
|
||||
|
||||
#pragma once
|
||||
@@ -7,21 +7,21 @@ namespace Easing {
|
||||
|
||||
// Ease-out quadratic: empieza rápido, desacelera suavemente
|
||||
// t = progreso normalizado [0.0 - 1.0]
|
||||
// retorna valor interpolado [0.0 - 1.0]
|
||||
// retorna value interpolado [0.0 - 1.0]
|
||||
inline float ease_out_quad(float t) {
|
||||
return 1.0F - ((1.0F - t) * (1.0F - t));
|
||||
}
|
||||
|
||||
// Ease-in quadratic: empieza lento, acelera
|
||||
// t = progreso normalizado [0.0 - 1.0]
|
||||
// retorna valor interpolado [0.0 - 1.0]
|
||||
// retorna value interpolado [0.0 - 1.0]
|
||||
inline float ease_in_quad(float t) {
|
||||
return t * t;
|
||||
}
|
||||
|
||||
// Ease-in-out quadratic: acelera al inicio, desacelera al final
|
||||
// t = progreso normalizado [0.0 - 1.0]
|
||||
// retorna valor interpolado [0.0 - 1.0]
|
||||
// retorna value interpolado [0.0 - 1.0]
|
||||
inline float ease_in_out_quad(float t) {
|
||||
return (t < 0.5F)
|
||||
? 2.0F * t * t
|
||||
@@ -30,7 +30,7 @@ inline float ease_in_out_quad(float t) {
|
||||
|
||||
// Ease-out cubic: desaceleración más suave que quadratic
|
||||
// t = progreso normalizado [0.0 - 1.0]
|
||||
// retorna valor interpolado [0.0 - 1.0]
|
||||
// retorna value interpolado [0.0 - 1.0]
|
||||
inline float ease_out_cubic(float t) {
|
||||
float t1 = 1.0F - t;
|
||||
return 1.0F - (t1 * t1 * t1);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// collision.hpp - Utilitats de detecció de col·lisions
|
||||
// collision.hpp - Utilitats de detecció de colisiones
|
||||
// © 2025 Orni Attack - Sistema de física
|
||||
|
||||
#pragma once
|
||||
@@ -8,18 +8,18 @@
|
||||
|
||||
namespace Physics {
|
||||
|
||||
// Comprovació genèrica de col·lisió entre dues entitats
|
||||
// Comprobación genèrica de colisión entre dues entidades
|
||||
inline bool check_collision(const Entities::Entity& a, const Entities::Entity& b, float amplifier = 1.0F) {
|
||||
// Comprovar si ambdós són col·lisionables
|
||||
if (!a.isCollidable() || !b.isCollidable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calcular radi combinat (amb amplificador per hitbox generós)
|
||||
// Calcular radi combinat (con amplificador per hitbox generós)
|
||||
float suma_radis = (a.getCollisionRadius() + b.getCollisionRadius()) * amplifier;
|
||||
float suma_radis_sq = suma_radis * suma_radis;
|
||||
|
||||
// Comprovació distància al quadrat (sense sqrt)
|
||||
// Comprobación distancia al cuadrado (sin sqrt)
|
||||
const Vec2& pos_a = a.getCenter();
|
||||
const Vec2& pos_b = b.getCenter();
|
||||
float dx = pos_a.x - pos_b.x;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// color_oscillator.cpp - Implementació d'oscil·lació de color
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// color_oscillator.cpp - Implementació de oscil·lació de color
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "core/rendering/color_oscillator.hpp"
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Rendering {
|
||||
|
||||
ColorOscillator::ColorOscillator()
|
||||
: accumulated_time_(0.0F) {
|
||||
// Inicialitzar amb el color mínim
|
||||
// Inicialitzar con el color mínim
|
||||
current_line_color_ = {.r = Defaults::Color::LINE_MIN_R,
|
||||
.g = Defaults::Color::LINE_MIN_G,
|
||||
.b = Defaults::Color::LINE_MIN_B,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// color_oscillator.hpp - Sistema d'oscil·lació de color per efecte CRT
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// color_oscillator.hpp - Sistema de oscil·lació de color per efecte CRT
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// coordinate_transform.cpp - Inicialització de variables globals
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// coordinate_transform.cpp - Inicialización de variables globals
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "core/rendering/coordinate_transform.hpp"
|
||||
|
||||
namespace Rendering {
|
||||
|
||||
// Factor d'scale global (inicialitzat a 1.0 per defecte)
|
||||
// Factor de scale global (inicialitzat a 1.0 per defecte)
|
||||
float g_current_scale_factor = 1.0F;
|
||||
|
||||
} // namespace Rendering
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// coordinate_transform.hpp - Transformació de coordenades lògiques a físiques
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
|
||||
namespace Rendering {
|
||||
|
||||
// Factor d'scale global (actualitzat cada frame per SDLManager)
|
||||
// Factor de scale global (actualitzat cada frame per SDLManager)
|
||||
extern float g_current_scale_factor;
|
||||
|
||||
// Transforma coordenada lògica a física amb arrodoniment
|
||||
// Transforma coordenada lógica a física con arrodoniment
|
||||
inline int transform_x(int logical_x, float scale) {
|
||||
return static_cast<int>(std::round(logical_x * scale));
|
||||
}
|
||||
@@ -19,7 +19,7 @@ inline int transform_y(int logical_y, float scale) {
|
||||
return static_cast<int>(std::round(logical_y * scale));
|
||||
}
|
||||
|
||||
// Variant que usa el factor d'scale global
|
||||
// Variant que usa el factor de scale global
|
||||
inline int transform_x(int logical_x) {
|
||||
return transform_x(logical_x, g_current_scale_factor);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// line_renderer.cpp - Implementació de renderitzat de línies
|
||||
// © 1999 Visente i Sergi (versió Pascal)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// line_renderer.cpp - Implementació de renderizado de línies
|
||||
// © 1999 Visente i Sergi (versión Pascal)
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "core/rendering/line_renderer.hpp"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// line_renderer.hpp - Renderitzat de línies
|
||||
// © 1999 Visente i Sergi (versió Pascal)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// line_renderer.hpp - Renderizado de línies
|
||||
// © 1999 Visente i Sergi (versión Pascal)
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
#include <SDL3/SDL.h>
|
||||
@@ -11,7 +11,7 @@ namespace Rendering {
|
||||
// brightness: factor de brightness (0.0-1.0, default 1.0 = màxima brightness).
|
||||
void linea(SDL_Renderer* renderer, int x1, int y1, int x2, int y2, float brightness = 1.0F);
|
||||
|
||||
// Estableix el color global de les línies (utilitzat per ColorOscillator).
|
||||
// Estableix el color global de las línies (utilitzat per ColorOscillator).
|
||||
void setLineColor(SDL_Color color);
|
||||
|
||||
} // namespace Rendering
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// sdl_manager.cpp - Implementació del gestor SDL3
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "sdl_manager.hpp"
|
||||
|
||||
@@ -38,13 +38,13 @@ SDLManager::SDLManager()
|
||||
// Calcular mida màxima des del display
|
||||
calculateMaxWindowSize();
|
||||
|
||||
// Construir títol dinàmic
|
||||
// Construir título dinàmic
|
||||
std::string window_title = std::format("{} v{} ({})", Project::LONG_NAME, Project::VERSION, Project::COPYRIGHT);
|
||||
|
||||
// Crear finestra CENTRADA (SDL ho fa automàticament amb CENTERED)
|
||||
// Crear finestra CENTRADA (SDL ho hace automàticament con CENTERED)
|
||||
finestra_ =
|
||||
SDL_CreateWindow(window_title.c_str(), current_width_, current_height_,
|
||||
SDL_WINDOW_RESIZABLE // Permetre resize manual també
|
||||
SDL_WINDOW_RESIZABLE // Permetre resize manual también
|
||||
);
|
||||
|
||||
if (finestra_ == nullptr) {
|
||||
@@ -56,7 +56,7 @@ SDLManager::SDLManager()
|
||||
// IMPORTANT: Centrar explícitament la finestra
|
||||
SDL_SetWindowPosition(finestra_, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
|
||||
|
||||
// Crear renderer amb acceleració
|
||||
// Crear renderer con aceleración
|
||||
renderer_ = SDL_CreateRenderer(finestra_, nullptr);
|
||||
|
||||
if (renderer_ == nullptr) {
|
||||
@@ -66,7 +66,7 @@ SDLManager::SDLManager()
|
||||
return;
|
||||
}
|
||||
|
||||
// Aplicar configuració de V-Sync
|
||||
// Aplicar configuración de V-Sync
|
||||
SDL_SetRenderVSync(renderer_, Options::rendering.vsync);
|
||||
|
||||
// CRÍTIC: Configurar viewport scaling
|
||||
@@ -77,7 +77,7 @@ SDLManager::SDLManager()
|
||||
<< Defaults::Game::HEIGHT << ")" << '\n';
|
||||
}
|
||||
|
||||
// Constructor amb configuració
|
||||
// Constructor con configuración
|
||||
SDLManager::SDLManager(int width, int height, bool fullscreen)
|
||||
: finestra_(nullptr),
|
||||
renderer_(nullptr),
|
||||
@@ -102,7 +102,7 @@ SDLManager::SDLManager(int width, int height, bool fullscreen)
|
||||
// Calcular mida màxima des del display
|
||||
calculateMaxWindowSize();
|
||||
|
||||
// Construir títol dinàmic
|
||||
// Construir título dinàmic
|
||||
std::string window_title = std::format("{} v{} ({})", Project::LONG_NAME, Project::VERSION, Project::COPYRIGHT);
|
||||
|
||||
// Configurar flags de la finestra
|
||||
@@ -120,12 +120,12 @@ SDLManager::SDLManager(int width, int height, bool fullscreen)
|
||||
return;
|
||||
}
|
||||
|
||||
// Centrar explícitament la finestra (si no és fullscreen)
|
||||
// Centrar explícitament la finestra (si no es fullscreen)
|
||||
if (!is_fullscreen_) {
|
||||
SDL_SetWindowPosition(finestra_, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
|
||||
}
|
||||
|
||||
// Crear renderer amb acceleració
|
||||
// Crear renderer con aceleración
|
||||
renderer_ = SDL_CreateRenderer(finestra_, nullptr);
|
||||
|
||||
if (renderer_ == nullptr) {
|
||||
@@ -135,7 +135,7 @@ SDLManager::SDLManager(int width, int height, bool fullscreen)
|
||||
return;
|
||||
}
|
||||
|
||||
// Aplicar configuració de V-Sync
|
||||
// Aplicar configuración de V-Sync
|
||||
SDL_SetRenderVSync(renderer_, Options::rendering.vsync);
|
||||
|
||||
// Configurar viewport scaling
|
||||
@@ -176,7 +176,7 @@ void SDLManager::calculateMaxWindowSize() {
|
||||
const SDL_DisplayMode* mode = SDL_GetCurrentDisplayMode(display);
|
||||
|
||||
if (mode != nullptr) {
|
||||
// Deixar marge de 100px per a decoracions de l'OS
|
||||
// Deixar marge de 100px para decoracions de l'OS
|
||||
max_width_ = mode->w - 100;
|
||||
max_height_ = mode->h - 100;
|
||||
std::cout << "Display detectat: " << mode->w << "x" << mode->h
|
||||
@@ -253,9 +253,9 @@ void SDLManager::applyZoom(float new_zoom) {
|
||||
}
|
||||
|
||||
void SDLManager::updateLogicalPresentation() {
|
||||
// CANVIAT: Ja no usem SDL_SetRenderLogicalPresentation
|
||||
// CANVIAT: Ya no usem SDL_SetRenderLogicalPresentation
|
||||
// Ara renderitzem directament a resolució física per evitar pixelació irregular
|
||||
// El viewport amb letterbox es configura a updateViewport()
|
||||
// El viewport con letterbox es configura a updateViewport()
|
||||
updateViewport();
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ void SDLManager::updateViewport() {
|
||||
int scaled_width = static_cast<int>(std::round(Defaults::Game::WIDTH * scale));
|
||||
int scaled_height = static_cast<int>(std::round(Defaults::Game::HEIGHT * scale));
|
||||
|
||||
// Càlcul de letterbox (centrar l'àrea escalada)
|
||||
// Cálculo de letterbox (centrar l'àrea scaled)
|
||||
int offset_x = (current_width_ - scaled_width) / 2;
|
||||
int offset_y = (current_height_ - scaled_height) / 2;
|
||||
|
||||
@@ -273,7 +273,7 @@ void SDLManager::updateViewport() {
|
||||
offset_x = std::max(offset_x, 0);
|
||||
offset_y = std::max(offset_y, 0);
|
||||
|
||||
// Configurar viewport per al renderitzat
|
||||
// Configurar viewport per al renderizado
|
||||
SDL_Rect viewport = {offset_x, offset_y, scaled_width, scaled_height};
|
||||
SDL_SetRenderViewport(renderer_, &viewport);
|
||||
|
||||
@@ -283,7 +283,7 @@ void SDLManager::updateViewport() {
|
||||
}
|
||||
|
||||
void SDLManager::updateRenderingContext() const {
|
||||
// Actualitzar el factor d'scale global per a totes les funcions de renderitzat
|
||||
// Actualitzar el factor de scale global para todas las funciones de renderizado
|
||||
Rendering::g_current_scale_factor = zoom_factor_;
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@ void SDLManager::decreaseWindowSize() {
|
||||
}
|
||||
|
||||
void SDLManager::applyWindowSize(int new_width, int new_height) {
|
||||
// Obtenir posició actual ABANS del resize
|
||||
// Obtenir posición actual ABANS del resize
|
||||
int old_x;
|
||||
int old_y;
|
||||
SDL_GetWindowPosition(finestra_, &old_x, &old_y);
|
||||
@@ -324,7 +324,7 @@ void SDLManager::applyWindowSize(int new_width, int new_height) {
|
||||
current_height_ = new_height;
|
||||
|
||||
// CENTRADO INTEL·LIGENT (algoritme de pollo)
|
||||
// Calcular nova posició per mantenir la finestra centrada sobre si mateixa
|
||||
// Calcular nueva posición per mantenir la finestra centrada sobre si misma
|
||||
int delta_width = old_width - new_width;
|
||||
int delta_height = old_height - new_height;
|
||||
|
||||
@@ -332,13 +332,13 @@ void SDLManager::applyWindowSize(int new_width, int new_height) {
|
||||
int new_y = old_y + (delta_height / 2);
|
||||
|
||||
// Evitar que la finestra surti de la pantalla
|
||||
constexpr int TITLEBAR_HEIGHT = 35; // Alçada aproximada de la barra de títol
|
||||
constexpr int TITLEBAR_HEIGHT = 35; // Alçada aproximada de la barra de título
|
||||
new_x = std::max(new_x, 0);
|
||||
new_y = std::max(new_y, TITLEBAR_HEIGHT);
|
||||
|
||||
SDL_SetWindowPosition(finestra_, new_x, new_y);
|
||||
|
||||
// Actualitzar viewport després del resize
|
||||
// Actualitzar viewport después del resize
|
||||
updateViewport();
|
||||
}
|
||||
|
||||
@@ -368,7 +368,7 @@ void SDLManager::toggleFullscreen() {
|
||||
Options::window.fullscreen = is_fullscreen_;
|
||||
|
||||
// Notificar al mòdul Mouse: Fullscreen requereix ocultació permanent del cursor.
|
||||
// Quan es surt de fullscreen, restaurar el comportament normal d'auto-ocultació.
|
||||
// Cuando es surt de fullscreen, restaurar el comportament normal de auto-ocultació.
|
||||
Mouse::setForceHidden(is_fullscreen_);
|
||||
}
|
||||
|
||||
@@ -387,7 +387,7 @@ bool SDLManager::handleWindowEvent(const SDL_Event& event) {
|
||||
windowed_height_ = current_height_;
|
||||
}
|
||||
|
||||
// Actualitzar viewport després del resize manual
|
||||
// Actualitzar viewport después del resize manual
|
||||
updateViewport();
|
||||
|
||||
std::cout << "Finestra redimensionada: " << current_width_
|
||||
@@ -398,12 +398,12 @@ bool SDLManager::handleWindowEvent(const SDL_Event& event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void SDLManager::neteja(uint8_t r, uint8_t g, uint8_t b) {
|
||||
void SDLManager::clear(uint8_t r, uint8_t g, uint8_t b) {
|
||||
if (renderer_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// [MODIFICAT] Usar color oscil·lat del fons en lloc dels paràmetres
|
||||
// [MODIFICAT] Usar color oscil·lat del fons en lloc dels parámetros
|
||||
(void)r;
|
||||
(void)g;
|
||||
(void)b; // Suprimir warnings
|
||||
@@ -412,7 +412,7 @@ void SDLManager::neteja(uint8_t r, uint8_t g, uint8_t b) {
|
||||
SDL_RenderClear(renderer_);
|
||||
}
|
||||
|
||||
void SDLManager::presenta() {
|
||||
void SDLManager::present() {
|
||||
if (renderer_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -420,7 +420,7 @@ void SDLManager::presenta() {
|
||||
SDL_RenderPresent(renderer_);
|
||||
}
|
||||
|
||||
// [NUEVO] Actualitzar colors amb oscil·lació
|
||||
// [NUEVO] Actualitzar colors con oscil·lació
|
||||
void SDLManager::updateColors(float delta_time) {
|
||||
color_oscillator_.update(delta_time);
|
||||
|
||||
@@ -428,7 +428,7 @@ void SDLManager::updateColors(float delta_time) {
|
||||
Rendering::setLineColor(color_oscillator_.getCurrentLineColor());
|
||||
}
|
||||
|
||||
// [NUEVO] Actualitzar comptador de FPS
|
||||
// [NUEVO] Actualitzar counter de FPS
|
||||
void SDLManager::updateFPS(float delta_time) {
|
||||
// Acumular time i frames
|
||||
fps_accumulator_ += delta_time;
|
||||
@@ -440,7 +440,7 @@ void SDLManager::updateFPS(float delta_time) {
|
||||
fps_frame_count_ = 0;
|
||||
fps_accumulator_ = 0.0F;
|
||||
|
||||
// Actualitzar títol de la finestra
|
||||
// Actualitzar título de la finestra
|
||||
std::string vsync_state = (Options::rendering.vsync == 1) ? "ON" : "OFF";
|
||||
std::string title = std::format("{} v{} ({}) - {} FPS - VSync: {}",
|
||||
Project::LONG_NAME,
|
||||
@@ -455,7 +455,7 @@ void SDLManager::updateFPS(float delta_time) {
|
||||
}
|
||||
}
|
||||
|
||||
// [NUEVO] Actualitzar títol de la finestra
|
||||
// [NUEVO] Actualitzar título de la finestra
|
||||
void SDLManager::setWindowTitle(const std::string& title) {
|
||||
if (finestra_ != nullptr) {
|
||||
SDL_SetWindowTitle(finestra_, title.c_str());
|
||||
@@ -476,6 +476,6 @@ void SDLManager::toggleVSync() {
|
||||
fps_accumulator_ = 0.0F;
|
||||
fps_frame_count_ = 0;
|
||||
|
||||
// Guardar configuració
|
||||
// Guardar configuración
|
||||
Options::saveToFile();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// sdl_manager.hpp - Gestor d'inicialització de SDL3
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// sdl_manager.hpp - Gestor de inicialización de SDL3
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#ifndef SDL_MANAGER_HPP
|
||||
#define SDL_MANAGER_HPP
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
@@ -14,7 +13,7 @@
|
||||
class SDLManager {
|
||||
public:
|
||||
SDLManager(); // Constructor per defecte (usa Defaults::)
|
||||
SDLManager(int width, int height, bool fullscreen); // Constructor amb configuració
|
||||
SDLManager(int width, int height, bool fullscreen); // Constructor con configuración
|
||||
~SDLManager();
|
||||
|
||||
// No permetre còpia ni assignació
|
||||
@@ -28,24 +27,24 @@ class SDLManager {
|
||||
void toggleVSync(); // F4
|
||||
bool handleWindowEvent(const SDL_Event& event); // Per a SDL_EVENT_WINDOW_RESIZED
|
||||
|
||||
// Funcions principals (renderitzat)
|
||||
void neteja(uint8_t r = 0, uint8_t g = 0, uint8_t b = 0);
|
||||
void presenta();
|
||||
// Funciones principals (renderizado)
|
||||
void clear(uint8_t r = 0, uint8_t g = 0, uint8_t b = 0);
|
||||
void present();
|
||||
|
||||
// [NUEVO] Actualització de colors (oscil·lació)
|
||||
void updateColors(float delta_time);
|
||||
|
||||
// [NUEVO] Actualitzar comptador de FPS
|
||||
// [NUEVO] Actualitzar counter de FPS
|
||||
void updateFPS(float delta_time);
|
||||
|
||||
// Getters
|
||||
SDL_Renderer* getRenderer() { return renderer_; }
|
||||
[[nodiscard]] float getScaleFactor() const { return zoom_factor_; }
|
||||
|
||||
// [NUEVO] Actualitzar títol de la finestra
|
||||
// [NUEVO] Actualitzar título de la finestra
|
||||
void setWindowTitle(const std::string& title);
|
||||
|
||||
// [NUEVO] Actualitzar context de renderitzat (factor d'scale global)
|
||||
// [NUEVO] Actualitzar context de renderizado (factor de scale global)
|
||||
void updateRenderingContext() const;
|
||||
|
||||
private:
|
||||
@@ -70,16 +69,14 @@ class SDLManager {
|
||||
int windowed_height_; // Saved size before fullscreen
|
||||
float max_zoom_; // Maximum zoom (calculated from display)
|
||||
|
||||
// [NUEVO] Funcions internes
|
||||
// [NUEVO] Funciones internes
|
||||
void calculateMaxWindowSize(); // Llegir resolució del display
|
||||
void calculateMaxZoom(); // Calculate max zoom from display
|
||||
void applyZoom(float new_zoom); // Apply zoom and resize window
|
||||
void applyWindowSize(int width, int height); // Canviar mida + centrar
|
||||
void updateLogicalPresentation(); // Actualitzar viewport
|
||||
void updateViewport(); // Configurar viewport amb letterbox
|
||||
void updateViewport(); // Configurar viewport con letterbox
|
||||
|
||||
// [NUEVO] Oscil·lador de colors
|
||||
Rendering::ColorOscillator color_oscillator_;
|
||||
};
|
||||
|
||||
#endif // SDL_MANAGER_HPP
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// shape_renderer.cpp - Implementació del renderitzat de formes
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// shape_renderer.cpp - Implementació del renderizado de formes
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "core/rendering/shape_renderer.hpp"
|
||||
|
||||
@@ -10,65 +10,65 @@
|
||||
|
||||
namespace Rendering {
|
||||
|
||||
// Helper: aplicar rotació 3D a un point 2D (assumeix Z=0)
|
||||
// Helper: aplicar rotación 3D a un point 2D (assumeix Z=0)
|
||||
static Vec2 apply_3d_rotation(float x, float y, const Rotation3D& rot) {
|
||||
float z = 0.0F; // Tots els points 2D comencen a Z=0
|
||||
float z = 0.0F; // Todos los points 2D comencen a Z=0
|
||||
|
||||
// Pitch (rotació eix X): cabeceo arriba/baix
|
||||
// Pitch (rotación eix X): cabeceo arriba/baix
|
||||
float cos_pitch = std::cos(rot.pitch);
|
||||
float sin_pitch = std::sin(rot.pitch);
|
||||
float y1 = (y * cos_pitch) - (z * sin_pitch);
|
||||
float z1 = (y * sin_pitch) + (z * cos_pitch);
|
||||
|
||||
// Yaw (rotació eix Y): guiñada esquerra/dreta
|
||||
// Yaw (rotación eix Y): guiñada izquierda/derecha
|
||||
float cos_yaw = std::cos(rot.yaw);
|
||||
float sin_yaw = std::sin(rot.yaw);
|
||||
float x2 = (x * cos_yaw) + (z1 * sin_yaw);
|
||||
float z2 = (-x * sin_yaw) + (z1 * cos_yaw);
|
||||
|
||||
// Roll (rotació eix Z): alabeo lateral
|
||||
// Roll (rotación eix Z): alabeo lateral
|
||||
float cos_roll = std::cos(rot.roll);
|
||||
float sin_roll = std::sin(rot.roll);
|
||||
float x3 = (x2 * cos_roll) - (y1 * sin_roll);
|
||||
float y3 = (x2 * sin_roll) + (y1 * cos_roll);
|
||||
|
||||
// Proyecció perspectiva (Z-divide simple)
|
||||
// Naus volen cap al point de fuga (320, 240) a "infinit" (Z → +∞)
|
||||
// Z més gran = més lluny = més petit a pantalla
|
||||
// Naves quieren hacia el point de fuga (320, 240) a "infinit" (Z → +∞)
|
||||
// Z més grande = més lluny = més pequeño a pantalla
|
||||
constexpr float perspective_factor = 500.0F;
|
||||
float scale_factor = perspective_factor / (perspective_factor + z2);
|
||||
|
||||
return {.x = x3 * scale_factor, .y = y3 * scale_factor};
|
||||
}
|
||||
|
||||
// Helper: transformar un point amb rotació, scale i trasllació
|
||||
// Helper: transformar un point con rotación, scale i traslación
|
||||
static Vec2 transform_point(const Vec2& point, const Vec2& shape_centre, const Vec2& position, float angle, float scale, const Rotation3D* rotation_3d) {
|
||||
// 1. Centrar el point respecte al centre de la shape
|
||||
// 1. Centrar el point respecte al centro de la shape
|
||||
float centered_x = point.x - shape_centre.x;
|
||||
float centered_y = point.y - shape_centre.y;
|
||||
|
||||
// 2. Aplicar rotació 3D (si es proporciona)
|
||||
// 2. Aplicar rotación 3D (si es proporciona)
|
||||
if ((rotation_3d != nullptr) && rotation_3d->has_rotation()) {
|
||||
Vec2 rotated_3d = apply_3d_rotation(centered_x, centered_y, *rotation_3d);
|
||||
centered_x = rotated_3d.x;
|
||||
centered_y = rotated_3d.y;
|
||||
}
|
||||
|
||||
// 3. Aplicar scale al point (després de rotació 3D)
|
||||
// 3. Aplicar scale al point (después de rotación 3D)
|
||||
float scaled_x = centered_x * scale;
|
||||
float scaled_y = centered_y * scale;
|
||||
|
||||
// 4. Aplicar rotació 2D (Z-axis, tradicional)
|
||||
// IMPORTANT: En el sistema original, angle=0 apunta AMUNT (no dreta)
|
||||
// 4. Aplicar rotación 2D (Z-axis, tradicional)
|
||||
// IMPORTANT: En el sistema original, angle=0 apunta AMUNT (no derecha)
|
||||
// Per això usem (angle - PI/2) per compensar
|
||||
// Però aquí angle ja ve en el sistema correcte del joc
|
||||
// Pero aquí angle ya ve en el sistema correcte del juego
|
||||
float cos_a = std::cos(angle);
|
||||
float sin_a = std::sin(angle);
|
||||
|
||||
float rotated_x = (scaled_x * cos_a) - (scaled_y * sin_a);
|
||||
float rotated_y = (scaled_x * sin_a) + (scaled_y * cos_a);
|
||||
|
||||
// 5. Aplicar trasllació a posició mundial
|
||||
// 5. Aplicar traslación a posición mundial
|
||||
return {.x = rotated_x + position.x, .y = rotated_y + position.y};
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ void render_shape(SDL_Renderer* renderer,
|
||||
float progress,
|
||||
float brightness,
|
||||
const Rotation3D* rotation_3d) {
|
||||
// Verificar que la shape és vàlida
|
||||
// Verificar que la shape es vàlida
|
||||
if (!shape || !shape->isValid()) {
|
||||
return;
|
||||
}
|
||||
@@ -90,10 +90,10 @@ void render_shape(SDL_Renderer* renderer,
|
||||
return;
|
||||
}
|
||||
|
||||
// Obtenir el centre de la shape per a transformacions
|
||||
// Obtenir el centro de la shape para transformacions
|
||||
const Vec2& shape_centre = shape->getCenter();
|
||||
|
||||
// Iterar sobre totes les primitives
|
||||
// Iterar sobre todas las primitives
|
||||
for (const auto& primitive : shape->get_primitives()) {
|
||||
if (primitive.type == Graphics::PrimitiveType::POLYLINE) {
|
||||
// POLYLINE: connectar points consecutius
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// shape_renderer.hpp - Renderitzat de formes vectorials
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// shape_renderer.hpp - Renderizado de formes vectorials
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -14,9 +14,9 @@ namespace Rendering {
|
||||
|
||||
// Estructura per rotacions 3D (pitch, yaw, roll)
|
||||
struct Rotation3D {
|
||||
float pitch; // Rotació eix X (cabeceo arriba/baix)
|
||||
float yaw; // Rotació eix Y (guiñada esquerra/dreta)
|
||||
float roll; // Rotació eix Z (alabeo lateral)
|
||||
float pitch; // Rotación eix X (cabeceo arriba/baix)
|
||||
float yaw; // Rotación eix Y (guiñada izquierda/derecha)
|
||||
float roll; // Rotación eix Z (alabeo lateral)
|
||||
|
||||
Rotation3D()
|
||||
: pitch(0.0F),
|
||||
@@ -32,13 +32,13 @@ struct Rotation3D {
|
||||
}
|
||||
};
|
||||
|
||||
// Renderitzar shape amb transformacions
|
||||
// Renderizar shape con transformacions
|
||||
// - renderer: SDL renderer
|
||||
// - shape: shape vectorial a draw
|
||||
// - position: posició del centre en coordenades mundials
|
||||
// - angle: rotació en radians (0 = amunt, sentit horari)
|
||||
// - scale: factor d'scale (1.0 = mida original)
|
||||
// - progress: progrés de l'animació (0.0-1.0, default 1.0 = tot visible)
|
||||
// - position: posición del centro en coordenades mundials
|
||||
// - angle: rotación en radians (0 = amunt, sentit horari)
|
||||
// - scale: factor de scale (1.0 = mida original)
|
||||
// - progress: progrés de l'animación (0.0-1.0, default 1.0 = tot visible)
|
||||
// - brightness: factor de brightness (0.0-1.0, default 1.0 = màxima brightness)
|
||||
void render_shape(SDL_Renderer* renderer,
|
||||
const std::shared_ptr<Graphics::Shape>& shape,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// resource_helper.cpp - Implementació de funcions d'ajuda
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// resource_helper.cpp - Implementació de funciones de ajuda
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "resource_helper.hpp"
|
||||
|
||||
@@ -15,7 +15,7 @@ bool initializeResourceSystem(const std::string& pack_file, bool fallback) {
|
||||
return Loader::get().initialize(pack_file, fallback);
|
||||
}
|
||||
|
||||
// Carregar un fitxer
|
||||
// Carregar un file
|
||||
std::vector<uint8_t> loadFile(const std::string& filepath) {
|
||||
// Normalitzar la ruta
|
||||
std::string normalized = normalizePath(filepath);
|
||||
@@ -24,7 +24,7 @@ std::vector<uint8_t> loadFile(const std::string& filepath) {
|
||||
return Loader::get().loadResource(normalized);
|
||||
}
|
||||
|
||||
// Comprovar si existeix un fitxer
|
||||
// Comprovar si existeix un file
|
||||
bool fileExists(const std::string& filepath) {
|
||||
std::string normalized = normalizePath(filepath);
|
||||
return Loader::get().resourceExists(normalized);
|
||||
@@ -37,7 +37,7 @@ std::string getPackPath(const std::string& asset_path) {
|
||||
|
||||
// Eliminar rutes absolutes (detectar / o C:\ al principi)
|
||||
if (!path.empty() && path[0] == '/') {
|
||||
// Buscar "data/" i agafar el que ve després
|
||||
// Buscar "data/" i agafar el que ve después
|
||||
size_t data_pos = path.find("/data/");
|
||||
if (data_pos != std::string::npos) {
|
||||
path = path.substr(data_pos + 6); // Saltar "/data/"
|
||||
@@ -73,7 +73,7 @@ std::string normalizePath(const std::string& path) {
|
||||
return getPackPath(path);
|
||||
}
|
||||
|
||||
// Comprovar si hi ha paquet carregat
|
||||
// Comprovar si hay paquet carregat
|
||||
bool isPackLoaded() {
|
||||
return Loader::get().isPackLoaded();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// resource_helper.hpp - Funcions d'ajuda per gestió de recursos
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// resource_helper.hpp - Funciones de ajuda per gestió de recursos
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
// API simplificada i normalització de rutes
|
||||
|
||||
#pragma once
|
||||
@@ -10,10 +10,10 @@
|
||||
|
||||
namespace Resource::Helper {
|
||||
|
||||
// Inicialització del sistema
|
||||
// Inicialización del sistema
|
||||
bool initializeResourceSystem(const std::string& pack_file, bool fallback);
|
||||
|
||||
// Càrrega de fitxers
|
||||
// Càrrega de archivos
|
||||
std::vector<uint8_t> loadFile(const std::string& filepath);
|
||||
bool fileExists(const std::string& filepath);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// resource_loader.cpp - Implementació del carregador de recursos
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "resource_loader.hpp"
|
||||
|
||||
@@ -25,12 +25,12 @@ bool Loader::initialize(const std::string& pack_file, bool enable_fallback) {
|
||||
if (!pack_->loadPack(pack_file)) {
|
||||
if (!fallback_enabled_) {
|
||||
std::cerr << "[ResourceLoader] ERROR FATAL: No es pot load " << pack_file
|
||||
<< " i el fallback està desactivat\n";
|
||||
<< " y el fallback está desactivat\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "[ResourceLoader] Paquet no trobat, usant fallback al sistema de fitxers\n";
|
||||
pack_.reset(); // No hi ha paquet
|
||||
std::cout << "[ResourceLoader] Paquet no trobat, usant fallback al sistema de archivos\n";
|
||||
pack_.reset(); // No hay paquet
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ std::vector<uint8_t> Loader::loadResource(const std::string& filename) {
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
// Si no està al paquet i no hi ha fallback, falla
|
||||
// Si no está al paquet y no hay fallback, falla
|
||||
if (!fallback_enabled_) {
|
||||
std::cerr << "[ResourceLoader] ERROR: Recurs no trobat al paquet i fallback desactivat: "
|
||||
<< filename << "\n";
|
||||
@@ -59,7 +59,7 @@ std::vector<uint8_t> Loader::loadResource(const std::string& filename) {
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback al sistema de fitxers
|
||||
// Fallback al sistema de archivos
|
||||
if (fallback_enabled_) {
|
||||
return loadFromFilesystem(filename);
|
||||
}
|
||||
@@ -74,7 +74,7 @@ bool Loader::resourceExists(const std::string& filename) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Comprovar al sistema de fitxers si està activat el fallback
|
||||
// Comprovar al sistema de archivos si está activat el fallback
|
||||
if (fallback_enabled_) {
|
||||
std::string fullpath = base_path_.empty() ? "data/" + filename : base_path_ + "/data/" + filename;
|
||||
return std::filesystem::exists(fullpath);
|
||||
@@ -86,14 +86,14 @@ bool Loader::resourceExists(const std::string& filename) {
|
||||
// Validar el paquet
|
||||
bool Loader::validatePack() {
|
||||
if (!pack_) {
|
||||
std::cerr << "[ResourceLoader] Advertència: no hi ha paquet carregat per validar\n";
|
||||
std::cerr << "[ResourceLoader] Advertència: no hay paquet carregat per validar\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return pack_->validatePack();
|
||||
}
|
||||
|
||||
// Comprovar si hi ha paquet carregat
|
||||
// Comprovar si hay paquet carregat
|
||||
bool Loader::isPackLoaded() const {
|
||||
return pack_ != nullptr;
|
||||
}
|
||||
@@ -109,7 +109,7 @@ std::string Loader::getBasePath() const {
|
||||
return base_path_;
|
||||
}
|
||||
|
||||
// Carregar des del sistema de fitxers (fallback)
|
||||
// Carregar des del sistema de archivos (fallback)
|
||||
std::vector<uint8_t> Loader::loadFromFilesystem(const std::string& filename) {
|
||||
// The filename is already normalized (e.g., "shapes/logo/letra_j.shp")
|
||||
// We need to prepend base_path + "data/"
|
||||
@@ -136,7 +136,7 @@ std::vector<uint8_t> Loader::loadFromFilesystem(const std::string& filename) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::cout << "[ResourceLoader] Carregat des del sistema de fitxers: " << fullpath << "\n";
|
||||
std::cout << "[ResourceLoader] Carregat des del sistema de archivos: " << fullpath << "\n";
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// resource_loader.hpp - Carregador de recursos (Singleton)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// Coordina càrrega des del paquet i/o sistema de fitxers
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
// Coordina càrrega des del paquet i/o sistema de archivos
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -18,7 +18,7 @@ class Loader {
|
||||
// Singleton
|
||||
static Loader& get();
|
||||
|
||||
// Inicialització
|
||||
// Inicialización
|
||||
bool initialize(const std::string& pack_file, bool enable_fallback);
|
||||
|
||||
// Càrrega de recursos
|
||||
@@ -46,7 +46,7 @@ class Loader {
|
||||
bool fallback_enabled_ = false;
|
||||
std::string base_path_;
|
||||
|
||||
// Funcions auxiliars
|
||||
// Funciones auxiliars
|
||||
std::vector<uint8_t> loadFromFilesystem(const std::string& filename);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// resource_pack.cpp - Implementació del sistema d'empaquetament
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// resource_pack.cpp - Implementació del sistema de empaquetament
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "resource_pack.hpp"
|
||||
|
||||
@@ -30,11 +30,11 @@ void Pack::encryptData(std::vector<uint8_t>& data, const std::string& key) {
|
||||
}
|
||||
|
||||
void Pack::decryptData(std::vector<uint8_t>& data, const std::string& key) {
|
||||
// XOR és simètric
|
||||
// XOR es simètric
|
||||
encryptData(data, key);
|
||||
}
|
||||
|
||||
// Llegir fitxer complet a memòria
|
||||
// Llegir file complet a memòria
|
||||
std::vector<uint8_t> Pack::readFile(const std::string& filepath) {
|
||||
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
@@ -54,7 +54,7 @@ std::vector<uint8_t> Pack::readFile(const std::string& filepath) {
|
||||
return data;
|
||||
}
|
||||
|
||||
// Afegir un fitxer individual al paquet
|
||||
// Añadir un file individual al paquet
|
||||
bool Pack::addFile(const std::string& filepath, const std::string& pack_name) {
|
||||
auto file_data = readFile(filepath);
|
||||
if (file_data.empty()) {
|
||||
@@ -67,17 +67,17 @@ bool Pack::addFile(const std::string& filepath, const std::string& pack_name) {
|
||||
.size = file_data.size(),
|
||||
.checksum = calculateChecksum(file_data)};
|
||||
|
||||
// Afegir dades al bloc de dades
|
||||
// Añadir dades al bloc de dades
|
||||
data_.insert(data_.end(), file_data.begin(), file_data.end());
|
||||
|
||||
resources_[pack_name] = entry;
|
||||
|
||||
std::cout << "[ResourcePack] Afegit: " << pack_name << " (" << file_data.size()
|
||||
std::cout << "[ResourcePack] Añadido: " << pack_name << " (" << file_data.size()
|
||||
<< " bytes)\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Afegir tots els fitxers d'un directori recursivament
|
||||
// Añadir todos los archivos de un directori recursivament
|
||||
bool Pack::addDirectory(const std::string& dir_path,
|
||||
const std::string& base_path) {
|
||||
namespace fs = std::filesystem;
|
||||
@@ -100,7 +100,7 @@ bool Pack::addDirectory(const std::string& dir_path,
|
||||
// Convertir barres invertides a normals (Windows)
|
||||
std::ranges::replace(relative_path, '\\', '/');
|
||||
|
||||
// Saltar fitxers de desenvolupament
|
||||
// Saltar archivos de desenvolupament
|
||||
if (relative_path.find(".world") != std::string::npos ||
|
||||
relative_path.find(".tsx") != std::string::npos ||
|
||||
relative_path.find(".DS_Store") != std::string::npos ||
|
||||
@@ -134,7 +134,7 @@ bool Pack::savePack(const std::string& pack_file) {
|
||||
|
||||
// Escriure metadades de recursos
|
||||
for (const auto& [name, entry] : resources_) {
|
||||
// Nom del fitxer
|
||||
// Nom del file
|
||||
auto name_len = static_cast<uint32_t>(entry.filename.length());
|
||||
file.write(reinterpret_cast<const char*>(&name_len), sizeof(name_len));
|
||||
file.write(entry.filename.c_str(), name_len);
|
||||
@@ -149,7 +149,7 @@ bool Pack::savePack(const std::string& pack_file) {
|
||||
std::vector<uint8_t> encrypted_data = data_;
|
||||
encryptData(encrypted_data, DEFAULT_ENCRYPT_KEY);
|
||||
|
||||
// Escriure mida de dades i dades encriptades
|
||||
// Escriure mida de dades y dades encriptades
|
||||
auto data_size = static_cast<uint64_t>(encrypted_data.size());
|
||||
file.write(reinterpret_cast<const char*>(&data_size), sizeof(data_size));
|
||||
file.write(reinterpret_cast<const char*>(encrypted_data.data()), encrypted_data.size());
|
||||
@@ -160,7 +160,7 @@ bool Pack::savePack(const std::string& pack_file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Carregar paquet des de disc
|
||||
// Carregar paquet desde disc
|
||||
bool Pack::loadPack(const std::string& pack_file) {
|
||||
std::ifstream file(pack_file, std::ios::binary);
|
||||
if (!file) {
|
||||
@@ -180,7 +180,7 @@ bool Pack::loadPack(const std::string& pack_file) {
|
||||
uint32_t version;
|
||||
file.read(reinterpret_cast<char*>(&version), sizeof(version));
|
||||
if (version != VERSION) {
|
||||
std::cerr << "[ResourcePack] Error: versió incompatible (esperava " << VERSION
|
||||
std::cerr << "[ResourcePack] Error: versión incompatible (esperava " << VERSION
|
||||
<< ", trobat " << version << ")\n";
|
||||
return false;
|
||||
}
|
||||
@@ -192,7 +192,7 @@ bool Pack::loadPack(const std::string& pack_file) {
|
||||
// Llegir metadades de recursos
|
||||
resources_.clear();
|
||||
for (uint32_t i = 0; i < resource_count; ++i) {
|
||||
// Nom del fitxer
|
||||
// Nom del file
|
||||
uint32_t name_len;
|
||||
file.read(reinterpret_cast<char*>(&name_len), sizeof(name_len));
|
||||
|
||||
@@ -250,7 +250,7 @@ std::vector<uint8_t> Pack::getResource(const std::string& filename) {
|
||||
std::cerr << "[ResourcePack] ADVERTÈNCIA: checksum invàlid per " << filename
|
||||
<< " (esperat " << entry.checksum << ", calculat " << computed_checksum
|
||||
<< ")\n";
|
||||
// No falla, però adverteix
|
||||
// No falla, pero adverteix
|
||||
}
|
||||
|
||||
return resource_data;
|
||||
@@ -261,7 +261,7 @@ bool Pack::hasResource(const std::string& filename) const {
|
||||
return resources_.contains(filename);
|
||||
}
|
||||
|
||||
// Obtenir llista de tots els recursos
|
||||
// Obtenir list de todos los recursos
|
||||
std::vector<std::string> Pack::getResourceList() const {
|
||||
std::vector<std::string> list;
|
||||
list.reserve(resources_.size());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// resource_pack.hpp - Sistema d'empaquetament de recursos
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// Basat en el sistema de "pollo" amb adaptacions per Orni Attack
|
||||
// resource_pack.hpp - Sistema de empaquetament de recursos
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
// Basat en el sistema de "pollo" con adaptacions per Orni Attack
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -11,27 +11,27 @@
|
||||
|
||||
namespace Resource {
|
||||
|
||||
// Capçalera del fitxer de paquet
|
||||
// Capçalera del file de paquet
|
||||
struct PackHeader {
|
||||
char magic[4]; // "ORNI"
|
||||
uint32_t version; // Versió del format (1)
|
||||
uint32_t version; // Versión del format (1)
|
||||
};
|
||||
|
||||
// Entrada de recurs dins el paquet
|
||||
struct ResourceEntry {
|
||||
std::string filename; // Nom del recurs (amb barres normals)
|
||||
uint64_t offset; // Posició dins el bloc de dades
|
||||
std::string filename; // Nom del recurs (con barres normals)
|
||||
uint64_t offset; // Posición dins el bloc de dades
|
||||
uint64_t size; // Mida en bytes
|
||||
uint32_t checksum; // Checksum CRC32 per verificació
|
||||
};
|
||||
|
||||
// Classe principal per gestionar paquets de recursos
|
||||
// Clase principal per gestionar paquets de recursos
|
||||
class Pack {
|
||||
public:
|
||||
Pack() = default;
|
||||
~Pack() = default;
|
||||
|
||||
// Afegir fitxers al paquet
|
||||
// Añadir archivos al paquet
|
||||
bool addFile(const std::string& filepath, const std::string& pack_name);
|
||||
bool addDirectory(const std::string& dir_path, const std::string& base_path = "");
|
||||
|
||||
@@ -57,7 +57,7 @@ class Pack {
|
||||
std::unordered_map<std::string, ResourceEntry> resources_;
|
||||
std::vector<uint8_t> data_;
|
||||
|
||||
// Funcions auxiliars
|
||||
// Funciones auxiliars
|
||||
std::vector<uint8_t> readFile(const std::string& filepath);
|
||||
[[nodiscard]] uint32_t calculateChecksum(const std::vector<uint8_t>& data) const;
|
||||
void encryptData(std::vector<uint8_t>& data, const std::string& key);
|
||||
|
||||
@@ -36,7 +36,7 @@ using SceneType = SceneContext::SceneType;
|
||||
Director::Director(std::vector<std::string> const& args) {
|
||||
std::cout << "Orni Attack - Inici\n";
|
||||
|
||||
// Inicialitzar opcions amb valors per defecte
|
||||
// Inicialitzar opciones con valors per defecte
|
||||
Options::init();
|
||||
|
||||
// Comprovar arguments del programa
|
||||
@@ -50,28 +50,28 @@ Director::Director(std::vector<std::string> const& args) {
|
||||
|
||||
// Inicialitzar sistema de recursos
|
||||
#ifdef RELEASE_BUILD
|
||||
// Mode release: paquet obligatori, sense fallback
|
||||
// Mode release: paquet obligatori, sin fallback
|
||||
std::string pack_path = resource_base + "/resources.pack";
|
||||
if (!Resource::Helper::initializeResourceSystem(pack_path, false)) {
|
||||
std::cerr << "ERROR FATAL: No es pot load " << pack_path << "\n";
|
||||
std::cerr << "El joc no pot continuar sense els recursos.\n";
|
||||
std::cerr << "El juego no pot continuar sin los recursos.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Validar integritat del paquet
|
||||
if (!Resource::Loader::get().validatePack()) {
|
||||
std::cerr << "ERROR FATAL: El paquet de recursos està corromput\n";
|
||||
std::cerr << "ERROR FATAL: El paquet de recursos está corromput\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
std::cout << "Sistema de recursos inicialitzat (mode release)\n";
|
||||
#else
|
||||
// Mode desenvolupament: intentar paquet amb fallback a data/
|
||||
// Mode desenvolupament: intentar paquet con fallback a data/
|
||||
std::string pack_path = resource_base + "/resources.pack";
|
||||
Resource::Helper::initializeResourceSystem(pack_path, true);
|
||||
|
||||
if (Resource::Helper::isPackLoaded()) {
|
||||
std::cout << "Sistema de recursos inicialitzat (mode dev amb paquet)\n";
|
||||
std::cout << "Sistema de recursos inicialitzat (mode dev con paquet)\n";
|
||||
} else {
|
||||
std::cout << "Sistema de recursos inicialitzat (mode dev, fallback a data/)\n";
|
||||
}
|
||||
@@ -84,21 +84,21 @@ Director::Director(std::vector<std::string> const& args) {
|
||||
createSystemFolder("jailgames");
|
||||
createSystemFolder(std::string("jailgames/") + Project::NAME);
|
||||
|
||||
// Establir ruta del fitxer de configuració
|
||||
// Establir ruta del file de configuración
|
||||
Options::setConfigFile(system_folder_ + "/config.yaml");
|
||||
|
||||
// Carregar o crear configuració
|
||||
// Carregar o crear configuración
|
||||
Options::loadFromFile();
|
||||
|
||||
// Inicialitzar sistema d'input
|
||||
// Inicialitzar sistema de input
|
||||
Input::init("data/gamecontrollerdb.txt");
|
||||
|
||||
// Aplicar configuració de controls dels jugadors
|
||||
// Aplicar configuración de controls dels jugadors
|
||||
Input::get()->applyPlayer1BindingsFromOptions();
|
||||
Input::get()->applyPlayer2BindingsFromOptions();
|
||||
|
||||
if (Options::console) {
|
||||
std::cout << "Configuració carregada\n";
|
||||
std::cout << "Configuración carregada\n";
|
||||
std::cout << " Finestra: " << Options::window.width << "×"
|
||||
<< Options::window.height << '\n';
|
||||
std::cout << " Física: rotation=" << Options::physics.rotation_speed
|
||||
@@ -111,7 +111,7 @@ Director::Director(std::vector<std::string> const& args) {
|
||||
}
|
||||
|
||||
Director::~Director() {
|
||||
// Guardar opcions
|
||||
// Guardar opciones
|
||||
Options::saveToFile();
|
||||
|
||||
// Cleanup input
|
||||
@@ -138,7 +138,7 @@ auto Director::checkProgramArguments(std::vector<std::string> const& args)
|
||||
} else if (argument == "--reset-config") {
|
||||
Options::init();
|
||||
Options::saveToFile();
|
||||
std::cout << "Configuració restablida als valors per defecte\n";
|
||||
std::cout << "Configuración restablida als valors per defecte\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ void Director::createSystemFolder(const std::string& folder) {
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
case EEXIST:
|
||||
// La carpeta ja existeix (race condition), continuar
|
||||
// La carpeta ya existeix (race condition), continuar
|
||||
break;
|
||||
|
||||
case ENAMETOOLONG:
|
||||
@@ -207,7 +207,7 @@ void Director::createSystemFolder(const std::string& folder) {
|
||||
}
|
||||
}
|
||||
|
||||
// Bucle principal del joc
|
||||
// Bucle principal del juego
|
||||
auto Director::run() -> int {
|
||||
// Calculate initial size from saved zoom_factor
|
||||
int initial_width = static_cast<int>(std::round(
|
||||
@@ -215,16 +215,16 @@ auto Director::run() -> int {
|
||||
int initial_height = static_cast<int>(std::round(
|
||||
Defaults::Window::HEIGHT * Options::window.zoom_factor));
|
||||
|
||||
// Crear gestor SDL amb configuració de Options
|
||||
// Crear gestor SDL con configuración de Options
|
||||
SDLManager sdl(initial_width, initial_height, Options::window.fullscreen);
|
||||
|
||||
// CRÍTIC: Forçar ocultació del cursor DESPRÉS de tota la inicialització SDL
|
||||
// Això evita que SDL mostre el cursor automàticament durant la creació de la finestra
|
||||
// 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) {
|
||||
Mouse::forceHide();
|
||||
}
|
||||
|
||||
// Inicialitzar sistema d'audio
|
||||
// Inicialitzar sistema de audio
|
||||
Audio::init();
|
||||
Audio::get()->setMusicVolume(1.0);
|
||||
Audio::get()->setSoundVolume(0.4);
|
||||
@@ -234,10 +234,10 @@ auto Director::run() -> int {
|
||||
AudioCache::getMusic("game.ogg");
|
||||
if (Options::console) {
|
||||
std::cout << "Música precachejada: "
|
||||
<< AudioCache::getMusicCacheSize() << " fitxers\n";
|
||||
<< AudioCache::getMusicCacheSize() << " archivos\n";
|
||||
}
|
||||
|
||||
// Crear context d'escenes
|
||||
// Crear context de escenes
|
||||
SceneContext context;
|
||||
#ifdef _DEBUG
|
||||
context.setNextScene(SceneType::TITLE);
|
||||
@@ -245,10 +245,10 @@ auto Director::run() -> int {
|
||||
context.setNextScene(SceneType::LOGO);
|
||||
#endif
|
||||
|
||||
// Bucle principal de gestió d'escenes
|
||||
// Bucle principal de gestió de escenes
|
||||
while (context.nextScene() != SceneType::EXIT) {
|
||||
// Sincronitzar SceneManager::actual amb context
|
||||
// (altres sistemes encara poden llegir SceneManager::actual)
|
||||
// Sincronitzar SceneManager::actual con context
|
||||
// (altres sistemes aún poden llegir SceneManager::actual)
|
||||
SceneManager::actual = context.nextScene();
|
||||
|
||||
switch (context.nextScene()) {
|
||||
@@ -265,8 +265,8 @@ auto Director::run() -> int {
|
||||
}
|
||||
|
||||
case SceneType::GAME: {
|
||||
GameScene joc(sdl, context);
|
||||
joc.run();
|
||||
GameScene juego(sdl, context);
|
||||
juego.run();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -275,7 +275,7 @@ auto Director::run() -> int {
|
||||
}
|
||||
}
|
||||
|
||||
// Sincronitzar final amb SceneManager::actual
|
||||
// Sincronitzar final con SceneManager::actual
|
||||
SceneManager::actual = SceneType::EXIT;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -4,32 +4,32 @@
|
||||
|
||||
namespace GameConfig {
|
||||
|
||||
// Mode de joc
|
||||
// Mode de juego
|
||||
enum class Mode {
|
||||
NORMAL, // Partida normal
|
||||
DEMO // Mode demostració (futur)
|
||||
};
|
||||
|
||||
// Configuració d'una match
|
||||
// Configuración de una match
|
||||
struct MatchConfig {
|
||||
bool jugador1_actiu{false}; // És active el player 1?
|
||||
bool jugador2_actiu{false}; // És active el player 2?
|
||||
Mode mode{Mode::NORMAL}; // Mode de joc
|
||||
bool jugador1_actiu{false}; // Es active el player 1?
|
||||
bool jugador2_actiu{false}; // Es active el player 2?
|
||||
Mode mode{Mode::NORMAL}; // Mode de juego
|
||||
|
||||
// Mètodes auxiliars
|
||||
// Métodos auxiliars
|
||||
|
||||
// Retorna true si només hi ha un player active
|
||||
// Retorna true si solo hay un player active
|
||||
[[nodiscard]] bool es_un_jugador() const {
|
||||
return (jugador1_actiu && !jugador2_actiu) ||
|
||||
(!jugador1_actiu && jugador2_actiu);
|
||||
}
|
||||
|
||||
// Retorna true si hi ha dos jugadors active
|
||||
// Retorna true si hay dos jugadors active
|
||||
[[nodiscard]] bool son_dos_jugadors() const {
|
||||
return jugador1_actiu && jugador2_actiu;
|
||||
}
|
||||
|
||||
// Retorna true si no hi ha cap player active
|
||||
// Retorna true si no hay sin player active
|
||||
[[nodiscard]] bool cap_jugador() const {
|
||||
return !jugador1_actiu && !jugador2_actiu;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ struct MatchConfig {
|
||||
}
|
||||
|
||||
// Retorna l'ID de l'únic player active (0 o 1)
|
||||
// Només vàlid si es_un_jugador() retorna true
|
||||
// Solo vàlid si es_un_jugador() retorna true
|
||||
[[nodiscard]] uint8_t id_unic_jugador() const {
|
||||
if (jugador1_actiu && !jugador2_actiu) {
|
||||
return 0;
|
||||
@@ -48,7 +48,7 @@ struct MatchConfig {
|
||||
if (!jugador1_actiu && jugador2_actiu) {
|
||||
return 1;
|
||||
}
|
||||
return 0; // Fallback (cal comprovar es_un_jugador() primer)
|
||||
return 0; // Fallback (necesario comprovar es_un_jugador() primer)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// global_events.hpp - Events globals del joc
|
||||
// global_events.hpp - Events globals del juego
|
||||
// Basat en el patró del projecte "pollo"
|
||||
// © 2025 Port a C++20
|
||||
|
||||
@@ -14,6 +14,6 @@ class SceneContext;
|
||||
|
||||
namespace GlobalEvents {
|
||||
// Processa events globals (F1/F2/F3/ESC/QUIT)
|
||||
// Retorna true si l'event ha state processat i no cal seguir processant-lo
|
||||
// Retorna true si l'event ha state processat y no necesario seguir processant-lo
|
||||
bool handle(const SDL_Event& event, SDLManager& sdl, SceneManager::SceneContext& context);
|
||||
} // namespace GlobalEvents
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// context_escenes.hpp - Sistema de gestió d'escenes i context de transicions
|
||||
// scene_context.hpp - Sistema de gestió de escenes i context de transiciones
|
||||
// © 2025 Port a C++20
|
||||
|
||||
#pragma once
|
||||
@@ -7,29 +7,29 @@
|
||||
|
||||
namespace SceneManager {
|
||||
|
||||
// Context de transició entre escenes
|
||||
// Conté l'escena destinació i opcions específiques per aquella escena
|
||||
// Context de transición entre escenes
|
||||
// Conté l'escena destinació i opciones específiques per aquella escena
|
||||
class SceneContext {
|
||||
public:
|
||||
// Tipus d'escena del joc
|
||||
// Tipo de escena del juego
|
||||
enum class SceneType {
|
||||
LOGO, // Pantalla d'inici (logo JAILGAMES)
|
||||
TITLE, // Pantalla de títol amb menú
|
||||
GAME, // Joc principal (Asteroids)
|
||||
EXIT // Sortir del programa
|
||||
LOGO, // Pantalla de start (logo JAILGAMES)
|
||||
TITLE, // Pantalla de título con menú
|
||||
GAME, // Juego principal (Asteroids)
|
||||
EXIT // Salir del programa
|
||||
};
|
||||
|
||||
// Opcions específiques per a cada escena
|
||||
// Opciones específiques para cada escena
|
||||
enum class Option {
|
||||
NONE, // Sense opcions especials (comportament per defecte)
|
||||
NONE, // Sin opciones especials (comportament per defecte)
|
||||
JUMP_TO_TITLE_MAIN, // TITLE: Saltar directament a MAIN (starfield instantani)
|
||||
// MODE_DEMO, // GAME: Mode demostració amb IA (futur)
|
||||
// MODE_DEMO, // GAME: Mode demostració con IA (futur)
|
||||
};
|
||||
|
||||
// Constructor inicial amb escena LOGO i sense opcions
|
||||
// Constructor inicial con escena LOGO i sin opciones
|
||||
SceneContext() = default;
|
||||
|
||||
// Canviar escena amb opció específica
|
||||
// Canviar escena con opción específica
|
||||
void setNextScene(SceneType next_scene, Option option = Option::NONE) {
|
||||
next_scene_ = next_scene;
|
||||
option_ = option;
|
||||
@@ -40,42 +40,42 @@ class SceneContext {
|
||||
return next_scene_;
|
||||
}
|
||||
|
||||
// Consultar opció actual
|
||||
// Consultar opción actual
|
||||
[[nodiscard]] auto option() const -> Option {
|
||||
return option_;
|
||||
}
|
||||
|
||||
// Consumir opció (retorna valor i reseteja a NONE)
|
||||
// Utilitzar quan l'escena processa l'opció
|
||||
// Consumir opción (retorna value i reseteja a NONE)
|
||||
// Utilitzar cuando l'escena processa l'opción
|
||||
[[nodiscard]] auto consumeOption() -> Option {
|
||||
Option valor = option_;
|
||||
Option value = option_;
|
||||
option_ = Option::NONE;
|
||||
return valor;
|
||||
return value;
|
||||
}
|
||||
|
||||
// Reset opció a NONE (sense retornar valor)
|
||||
// Reset opción a NONE (sin retornar value)
|
||||
void resetOption() {
|
||||
option_ = Option::NONE;
|
||||
}
|
||||
|
||||
// Configurar match abans de transicionar a GAME
|
||||
// Configurar match antes de transicionar a GAME
|
||||
void setMatchConfig(const GameConfig::MatchConfig& config) {
|
||||
match_config_ = config;
|
||||
}
|
||||
|
||||
// Obtenir configuració de match (consumit per GameScene)
|
||||
// Obtenir configuración de match (consumit per GameScene)
|
||||
[[nodiscard]] const GameConfig::MatchConfig& getMatchConfig() const {
|
||||
return match_config_;
|
||||
}
|
||||
|
||||
private:
|
||||
SceneType next_scene_{SceneType::LOGO}; // SceneType a la qual transicionar
|
||||
Option option_{Option::NONE}; // Opció específica per l'escena
|
||||
GameConfig::MatchConfig match_config_; // Configuració de match (jugadors active, mode)
|
||||
Option option_{Option::NONE}; // Opción específica per l'escena
|
||||
GameConfig::MatchConfig match_config_; // Configuración de match (jugadors active, mode)
|
||||
};
|
||||
|
||||
// Variable global inline per gestionar l'escena actual (backward compatibility)
|
||||
// Sincronitzada amb context.nextScene() pel Director
|
||||
// Sincronitzada con context.nextScene() por el Director
|
||||
inline SceneContext::SceneType actual = SceneContext::SceneType::LOGO;
|
||||
|
||||
} // namespace SceneManager
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// path_utils.cpp - Implementació de utilitats de rutes
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "path_utils.hpp"
|
||||
|
||||
@@ -13,10 +13,10 @@ namespace Utils {
|
||||
static std::string executable_path_;
|
||||
static std::string executable_directory_;
|
||||
|
||||
// Inicialitzar el sistema de rutes amb argv[0]
|
||||
// Inicialitzar el sistema de rutes con argv[0]
|
||||
void initializePathSystem(const char* argv0) {
|
||||
if (argv0 == nullptr) {
|
||||
std::cerr << "[PathUtils] ADVERTÈNCIA: argv[0] és nullptr\n";
|
||||
std::cerr << "[PathUtils] ADVERTÈNCIA: argv[0] es nullptr\n";
|
||||
executable_path_ = "";
|
||||
executable_directory_ = ".";
|
||||
return;
|
||||
@@ -50,7 +50,7 @@ bool isMacOSBundle() {
|
||||
#ifdef MACOS_BUNDLE
|
||||
return true;
|
||||
#else
|
||||
// Detecció en time d'execució
|
||||
// Detecció en time de execució
|
||||
// Cercar ".app/Contents/MacOS" a la ruta de l'executable
|
||||
std::string exe_dir = getExecutableDirectory();
|
||||
return exe_dir.find(".app/Contents/MacOS") != std::string::npos;
|
||||
@@ -62,10 +62,10 @@ std::string getResourceBasePath() {
|
||||
std::string exe_dir = getExecutableDirectory();
|
||||
|
||||
if (isMacOSBundle()) {
|
||||
// Bundle de macOS: recursos a ../Resources des de MacOS/
|
||||
// Bundle de macOS: recursos a ../Resources desde MacOS/
|
||||
std::cout << "[PathUtils] Detectat bundle de macOS\n";
|
||||
return exe_dir + "/../Resources";
|
||||
} // Executable normal: recursos al mateix directori
|
||||
} // Executable normal: recursos al mismo directori
|
||||
return exe_dir;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ std::string normalizePath(const std::string& path) {
|
||||
// Convertir barres invertides a normals
|
||||
std::ranges::replace(normalized, '\\', '/');
|
||||
|
||||
// Simplificar rutes amb filesystem
|
||||
// Simplificar rutes con filesystem
|
||||
try {
|
||||
std::filesystem::path fs_path(normalized);
|
||||
normalized = fs_path.lexically_normal().string();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// path_utils.hpp - Utilitats de gestió de rutes
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
// Detecció de directoris i bundles multiplataforma
|
||||
|
||||
#pragma once
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
namespace Utils {
|
||||
|
||||
// Inicialització amb argv[0]
|
||||
// Inicialización con argv[0]
|
||||
void initializePathSystem(const char* argv0);
|
||||
|
||||
// Obtenció de rutes
|
||||
|
||||
Vendored
+116
-116
@@ -2,9 +2,9 @@
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_NODE_HPP
|
||||
@@ -25,9 +25,9 @@
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_MACROS_DEFINE_MACROS_HPP
|
||||
@@ -38,9 +38,9 @@
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Check version definitions if already defined.
|
||||
@@ -94,9 +94,9 @@
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_MACROS_CPP_CONFIG_MACROS_HPP
|
||||
@@ -109,7 +109,7 @@
|
||||
// With the MSVC compilers, the value of __cplusplus is by default always
|
||||
// "199611L"(C++98). To avoid that, the library instead references _MSVC_LANG
|
||||
// which is always set a correct value. See
|
||||
// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
|
||||
// https://devblogs.microsoft.como/cppblog/msvc-now-correctly-reports-__cplusplus/
|
||||
// for more details.
|
||||
#if defined(_MSVC_LANG) && !defined(__clang__)
|
||||
#define FK_YAML_CPLUSPLUS _MSVC_LANG
|
||||
@@ -265,9 +265,9 @@
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_ASSERT_HPP
|
||||
@@ -290,9 +290,9 @@
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_DOCUMENT_METAINFO_HPP
|
||||
@@ -308,9 +308,9 @@
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_META_NODE_TRAITS_HPP
|
||||
@@ -323,9 +323,9 @@
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_META_DETECT_HPP
|
||||
@@ -341,9 +341,9 @@
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_META_STL_SUPPLEMENT_HPP
|
||||
@@ -373,13 +373,13 @@ FK_YAML_DETAIL_NAMESPACE_BEGIN
|
||||
|
||||
/// @brief An alias template for std::add_pointer::type with C++11.
|
||||
/// @note std::add_pointer_t is available since C++14.
|
||||
/// @sa https://en.cppreference.com/w/cpp/types/add_pointer
|
||||
/// @sa https://en.cppreference.como/w/cpp/types/add_pointer
|
||||
/// @tparam T A type to be added a pointer.
|
||||
template <typename T> using add_pointer_t = typename std::add_pointer<T>::type;
|
||||
|
||||
/// @brief An alias template for std::enable_if::type with C++11.
|
||||
/// @note std::enable_if_t is available since C++14.
|
||||
/// @sa https://en.cppreference.com/w/cpp/types/enable_if
|
||||
/// @sa https://en.cppreference.como/w/cpp/types/enable_if
|
||||
/// @tparam Condition A condition tested at compile time.
|
||||
/// @tparam T The type defined only if Condition is true.
|
||||
template <bool Condition, typename T = void>
|
||||
@@ -387,7 +387,7 @@ using enable_if_t = typename std::enable_if<Condition, T>::type;
|
||||
|
||||
/// @brief A simple implementation to use std::is_null_pointer with C++11.
|
||||
/// @note std::is_null_pointer is available since C++14.
|
||||
/// @sa https://en.cppreference.com/w/cpp/types/is_null_pointer
|
||||
/// @sa https://en.cppreference.como/w/cpp/types/is_null_pointer
|
||||
/// @tparam T The type to be checked if it's equal to std::nullptr_t.
|
||||
template <typename T>
|
||||
struct is_null_pointer
|
||||
@@ -395,20 +395,20 @@ struct is_null_pointer
|
||||
|
||||
/// @brief An alias template for std::remove_cv::type with C++11.
|
||||
/// @note std::remove_cv_t is available since C++14.
|
||||
/// @sa https://en.cppreference.com/w/cpp/types/remove_cv
|
||||
/// @sa https://en.cppreference.como/w/cpp/types/remove_cv
|
||||
/// @tparam T A type from which const-volatile qualifiers are removed.
|
||||
template <typename T> using remove_cv_t = typename std::remove_cv<T>::type;
|
||||
|
||||
/// @brief An alias template for std::remove_pointer::type with C++11.
|
||||
/// @note std::remove_pointer_t is available since C++14.
|
||||
/// @sa https://en.cppreference.com/w/cpp/types/remove_pointer
|
||||
/// @sa https://en.cppreference.como/w/cpp/types/remove_pointer
|
||||
/// @tparam T A type from which a pointer is removed.
|
||||
template <typename T>
|
||||
using remove_pointer_t = typename std::remove_pointer<T>::type;
|
||||
|
||||
/// @brief An alias template for std::remove_reference::type with C++11.
|
||||
/// @note std::remove_reference_t is available since C++14.
|
||||
/// @sa https://en.cppreference.com/w/cpp/types/remove_reference
|
||||
/// @sa https://en.cppreference.como/w/cpp/types/remove_reference
|
||||
/// @tparam T A type from which a reference is removed.
|
||||
template <typename T>
|
||||
using remove_reference_t = typename std::remove_reference<T>::type;
|
||||
@@ -498,7 +498,7 @@ template <bool Val> using bool_constant = std::integral_constant<bool, Val>;
|
||||
/// @note
|
||||
/// std::conjunction is available since C++17.
|
||||
/// This is applied when no traits are specified as inputs.
|
||||
/// @sa https://en.cppreference.com/w/cpp/types/conjunction
|
||||
/// @sa https://en.cppreference.como/w/cpp/types/conjunction
|
||||
/// @tparam Traits Type traits to be checked if their ::value are all true.
|
||||
template <typename... Traits> struct conjunction : std::true_type {};
|
||||
|
||||
@@ -519,7 +519,7 @@ struct conjunction<First, Rest...>
|
||||
/// @note
|
||||
/// std::disjunction is available since C++17.
|
||||
/// This is applied when no traits are specified as inputs.
|
||||
/// @sa https://en.cppreference.com/w/cpp/types/disjunction
|
||||
/// @sa https://en.cppreference.como/w/cpp/types/disjunction
|
||||
/// @tparam Traits Type traits to be checked if at least one of their ::value is
|
||||
/// true.
|
||||
template <typename... Traits> struct disjunction : std::false_type {};
|
||||
@@ -539,7 +539,7 @@ struct disjunction<First, Rest...>
|
||||
|
||||
/// @brief A simple implementation to use std::negation with C++11/C++14.
|
||||
/// @note std::negation is available since C++17.
|
||||
/// @sa https://en.cppreference.com/w/cpp/types/negation
|
||||
/// @sa https://en.cppreference.como/w/cpp/types/negation
|
||||
/// @tparam Trait Type trait whose ::value is negated.
|
||||
template <typename Trait>
|
||||
struct negation : std::integral_constant<bool, !Trait::value> {};
|
||||
@@ -552,7 +552,7 @@ template <typename... Types> struct make_void {
|
||||
|
||||
/// @brief A simple implementation to use std::void_t with C++11/C++14.
|
||||
/// @note std::void_t is available since C++17.
|
||||
/// @sa https://en.cppreference.com/w/cpp/types/void_t
|
||||
/// @sa https://en.cppreference.como/w/cpp/types/void_t
|
||||
/// @tparam Types Any types to be transformed to void type.
|
||||
template <typename... Types> using void_t = typename make_void<Types...>::type;
|
||||
|
||||
@@ -571,7 +571,7 @@ using std::void_t;
|
||||
/// @brief A simple implementation to use std::remove_cvref_t with
|
||||
/// C++11/C++14/C++17.
|
||||
/// @note std::remove_cvref & std::remove_cvref_t are available since C++20.
|
||||
/// @sa https://en.cppreference.com/w/cpp/types/remove_cvref
|
||||
/// @sa https://en.cppreference.como/w/cpp/types/remove_cvref
|
||||
/// @tparam T A type from which cv-qualifiers and reference are removed.
|
||||
template <typename T>
|
||||
using remove_cvref_t =
|
||||
@@ -790,9 +790,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_META_TYPE_TRAITS_HPP
|
||||
@@ -890,9 +890,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_FKYAML_FWD_HPP
|
||||
@@ -1106,9 +1106,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_YAML_VERSION_TYPE_HPP
|
||||
@@ -1171,9 +1171,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_EXCEPTION_SAFE_ALLOCATION_HPP
|
||||
@@ -1278,9 +1278,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_INPUT_DESERIALIZER_HPP
|
||||
@@ -1299,9 +1299,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_INPUT_LEXICAL_ANALYZER_HPP
|
||||
@@ -1320,9 +1320,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_ENCODINGS_URI_ENCODING_HPP
|
||||
@@ -1453,9 +1453,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_ENCODINGS_UTF_ENCODINGS_HPP
|
||||
@@ -1471,9 +1471,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_EXCEPTION_HPP
|
||||
@@ -1491,9 +1491,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_STRING_FORMATTER_HPP
|
||||
@@ -1541,9 +1541,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_TYPES_NODE_T_HPP
|
||||
@@ -1558,9 +1558,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_NODE_TYPE_HPP
|
||||
@@ -2155,9 +2155,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_INPUT_BLOCK_SCALAR_HEADER_HPP
|
||||
@@ -2196,9 +2196,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_INPUT_POSITION_TRACKER_HPP
|
||||
@@ -2213,9 +2213,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_STR_VIEW_HPP
|
||||
@@ -3346,9 +3346,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_TYPES_LEXICAL_TOKEN_T_HPP
|
||||
@@ -4396,7 +4396,7 @@ private:
|
||||
if FK_YAML_UNLIKELY (cur_itr == m_end_itr) {
|
||||
// Without the following iterator update, lexer cannot reach the end of
|
||||
// input buffer and causes infinite loops from the next loop.
|
||||
// (https://github.com/fktn-k/fkYAML/pull/410)
|
||||
// (https://github.como/fktn-k/fkYAML/pull/410)
|
||||
m_cur_itr = m_end_itr;
|
||||
|
||||
// If there's no non-empty line, the content indentation level is equal to
|
||||
@@ -4726,9 +4726,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_INPUT_SCALAR_PARSER_HPP
|
||||
@@ -4743,9 +4743,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// **NOTE FOR LIBRARY DEVELOPERS**:
|
||||
@@ -5644,9 +5644,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_ENCODINGS_YAML_ESCAPER_HPP
|
||||
@@ -6005,9 +6005,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_INPUT_SCALAR_SCANNER_HPP
|
||||
@@ -6377,9 +6377,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_INPUT_TAG_T_HPP
|
||||
@@ -6948,7 +6948,7 @@ private:
|
||||
|
||||
// conversion error from a scalar which is not tagged with !!int is
|
||||
// recovered by treating it as a string scalar. See
|
||||
// https://github.com/fktn-k/fkYAML/issues/428.
|
||||
// https://github.como/fktn-k/fkYAML/issues/428.
|
||||
return basic_node_type(string_type(token.begin(), token.end()));
|
||||
}
|
||||
case node_type::FLOAT: {
|
||||
@@ -6966,7 +6966,7 @@ private:
|
||||
|
||||
// conversion error from a scalar which is not tagged with !!float is
|
||||
// recovered by treating it as a string scalar. See
|
||||
// https://github.com/fktn-k/fkYAML/issues/428.
|
||||
// https://github.como/fktn-k/fkYAML/issues/428.
|
||||
return basic_node_type(string_type(token.begin(), token.end()));
|
||||
}
|
||||
case node_type::STRING:
|
||||
@@ -7000,9 +7000,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_INPUT_TAG_RESOLVER_HPP
|
||||
@@ -7208,9 +7208,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_META_INPUT_ADAPTER_TRAITS_HPP
|
||||
@@ -7274,9 +7274,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_NODE_ATTRS_HPP
|
||||
@@ -7417,9 +7417,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_NODE_PROPERTY_HPP
|
||||
@@ -8019,7 +8019,7 @@ private:
|
||||
// (i.e., the properties are for a container node), the
|
||||
// application and the line advancement must happen here.
|
||||
// Otherwise, a false indent error will be emitted. See
|
||||
// https://github.com/fktn-k/fkYAML/issues/368 for more details.
|
||||
// https://github.como/fktn-k/fkYAML/issues/368 for more details.
|
||||
line = line_after_props;
|
||||
indent = lexer.get_last_token_begin_pos();
|
||||
*mp_current_node = basic_node_type::mapping();
|
||||
@@ -8910,9 +8910,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_INPUT_INPUT_ADAPTER_HPP
|
||||
@@ -8935,9 +8935,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_ENCODINGS_UTF_ENCODE_DETECTOR_HPP
|
||||
@@ -8953,9 +8953,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_ENCODINGS_UTF_ENCODE_T_HPP
|
||||
@@ -10496,9 +10496,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_ITERATOR_HPP
|
||||
@@ -10914,7 +10914,7 @@ namespace std {
|
||||
#ifdef __clang__
|
||||
// clang emits warnings against mixed usage of class/struct for
|
||||
// tuple_size/tuple_element. see also:
|
||||
// https://groups.google.com/a/isocpp.org/g/std-discussion/c/QC-AMb5oO1w
|
||||
// https://groups.google.como/a/isocpp.org/g/std-discussion/c/QC-AMb5oO1w
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||
#endif
|
||||
@@ -10949,9 +10949,9 @@ struct tuple_element<I, ::fkyaml::detail::iterator<ValueType>> {
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_MAP_RANGE_PROXY_HPP
|
||||
@@ -11139,9 +11139,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_NODE_REF_STORAGE_HPP
|
||||
@@ -11235,9 +11235,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_OUTPUT_SERIALIZER_HPP
|
||||
@@ -11255,9 +11255,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_CONVERSIONS_TO_STRING_HPP
|
||||
@@ -11337,7 +11337,7 @@ to_string(FloatType v, std::string &s) noexcept {
|
||||
|
||||
// If `v` is actually an integer and no scientific notation is used for
|
||||
// serialization, ".0" must be appended. The result would cause a roundtrip
|
||||
// issue otherwise. https://github.com/fktn-k/fkYAML/issues/405
|
||||
// issue otherwise. https://github.como/fktn-k/fkYAML/issues/405
|
||||
const std::size_t pos = s.find_first_of(".e");
|
||||
if (pos == std::string::npos) {
|
||||
s += ".0";
|
||||
@@ -11744,9 +11744,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_REVERSE_ITERATOR_HPP
|
||||
@@ -12016,9 +12016,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_TYPES_YAML_VERSION_T_HPP
|
||||
@@ -12073,9 +12073,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_NODE_VALUE_CONVERTER_HPP
|
||||
@@ -12090,9 +12090,9 @@ FK_YAML_DETAIL_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_CONVERSIONS_FROM_NODE_HPP
|
||||
@@ -12875,9 +12875,9 @@ FK_YAML_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_DETAIL_CONVERSIONS_TO_NODE_HPP
|
||||
@@ -13262,9 +13262,9 @@ FK_YAML_NAMESPACE_END
|
||||
// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML
|
||||
// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2
|
||||
// |__| |_| \__| |_| |_| |_|___||___|______|
|
||||
// https://github.com/fktn-k/fkYAML
|
||||
// https://github.como/fktn-k/fkYAML
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.como>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef FK_YAML_ORDERED_MAP_HPP
|
||||
@@ -13875,7 +13875,7 @@ public:
|
||||
/// iterators into a basic_node object.
|
||||
/// @note
|
||||
/// Iterators must satisfy the LegacyInputIterator requirements.
|
||||
/// See https://en.cppreference.com/w/cpp/named_req/InputIterator.
|
||||
/// See https://en.cppreference.como/w/cpp/named_req/InputIterator.
|
||||
/// @tparam ItrType Type of a compatible iterator
|
||||
/// @param[in] begin An iterator to the first element of an input sequence.
|
||||
/// @param[in] end An iterator to the past-the-last element of an input
|
||||
@@ -15517,7 +15517,7 @@ inline namespace yaml_literals {
|
||||
|
||||
// Whitespace before the literal operator identifier is deprecated in C++23 or
|
||||
// better but required in C++11. Ignore the warning as a workaround.
|
||||
// https://github.com/fktn-k/fkYAML/pull/417
|
||||
// https://github.como/fktn-k/fkYAML/pull/417
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
#include "core/defaults.hpp"
|
||||
|
||||
// Aliases per a backward compatibility amb codi existent
|
||||
// Aliases para backward compatibility con codi existent
|
||||
// Permet usar Constants::MARGIN_LEFT en lloc de Defaults::Game::MARGIN_LEFT
|
||||
|
||||
namespace Constants {
|
||||
// Marges de l'àrea de joc (derivats de Defaults::Zones::GAME)
|
||||
// Marges de l'àrea de juego (derivats de Defaults::Zones::GAME)
|
||||
constexpr int MARGIN_LEFT = static_cast<int>(Defaults::Zones::PLAYAREA.x);
|
||||
constexpr int MARGIN_RIGHT =
|
||||
static_cast<int>(Defaults::Zones::PLAYAREA.x + Defaults::Zones::PLAYAREA.w);
|
||||
@@ -14,7 +14,7 @@ constexpr int MARGIN_TOP = static_cast<int>(Defaults::Zones::PLAYAREA.y);
|
||||
constexpr int MARGIN_BOTTOM =
|
||||
static_cast<int>(Defaults::Zones::PLAYAREA.y + Defaults::Zones::PLAYAREA.h);
|
||||
|
||||
// Límits d'objectes
|
||||
// Límits de objectes
|
||||
constexpr int MAX_ORNIS = Defaults::Entities::MAX_ORNIS;
|
||||
constexpr int MAX_BALES = Defaults::Entities::MAX_BALES;
|
||||
|
||||
@@ -39,7 +39,7 @@ inline void obtenir_limits_zona(float& min_x, float& max_x, float& min_y, float&
|
||||
max_y = zona.y + zona.h;
|
||||
}
|
||||
|
||||
// Obtenir límits segurs (compensant radi de l'entitat)
|
||||
// Obtenir límits segurs (compensant radi de l'entidad)
|
||||
inline void obtenir_limits_zona_segurs(float radi, float& min_x, float& max_x, float& min_y, float& max_y) {
|
||||
const auto& zona = Defaults::Zones::PLAYAREA;
|
||||
constexpr float MARGE_SEGURETAT = 10.0F; // Safety margin
|
||||
@@ -50,7 +50,7 @@ inline void obtenir_limits_zona_segurs(float radi, float& min_x, float& max_x, f
|
||||
max_y = zona.y + zona.h - radi - MARGE_SEGURETAT;
|
||||
}
|
||||
|
||||
// Obtenir centre de l'àrea de joc
|
||||
// Obtenir centro de l'àrea de juego
|
||||
inline void obtenir_centre_zona(float& centre_x, float& centre_y) {
|
||||
const auto& zona = Defaults::Zones::PLAYAREA;
|
||||
centre_x = zona.x + (zona.w / 2.0F);
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
// debris.hpp - Fragment de línia volant (explosió de formes)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// debris.hpp - Fragment de línia volant (explosión de formes)
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
#include "core/types.hpp"
|
||||
|
||||
namespace Effects {
|
||||
|
||||
// Debris: un segment de línia que vola perpendicular a sí mateix
|
||||
// Representa un fragment d'una shape destruïda (ship, enemy, bullet)
|
||||
// Debris: un segment de línia que vola perpendicular a sí mismo
|
||||
// Representa un fragment de una shape destruïda (ship, enemy, bullet)
|
||||
struct Debris {
|
||||
// Geometria del segment (2 points en coordenades mundials)
|
||||
Vec2 p1; // Vec2 inicial del segment
|
||||
Vec2 p2; // Vec2 final del segment
|
||||
|
||||
// Física
|
||||
Vec2 velocity; // Velocitat en px/s (components x, y)
|
||||
float acceleration; // Acceleració negativa (fricció) en px/s²
|
||||
Vec2 velocity; // Velocidad en px/s (components x, y)
|
||||
float acceleration; // Aceleración negativa (fricció) en px/s²
|
||||
|
||||
// Rotació
|
||||
float angle_rotacio; // Angle de rotació acumulat (radians)
|
||||
float velocitat_rot; // Velocitat de rotació de TRAYECTORIA (rad/s)
|
||||
float velocitat_rot_visual; // Velocitat de rotació VISUAL del segment (rad/s)
|
||||
// Rotación
|
||||
float angle_rotacio; // Angle de rotación acumulat (radians)
|
||||
float velocitat_rot; // Velocidad de rotación de TRAYECTORIA (rad/s)
|
||||
float velocitat_rot_visual; // Velocidad de rotación VISUAL del segment (rad/s)
|
||||
|
||||
// Estat de vida
|
||||
float temps_vida; // Temps transcorregut (segons)
|
||||
float temps_max; // Temps de vida màxim (segons)
|
||||
bool active; // Està active?
|
||||
bool active; // Está active?
|
||||
|
||||
// Shrinking (reducció de distància entre points)
|
||||
// Shrinking (reducció de distancia entre points)
|
||||
float factor_shrink; // Factor de reducció per segon (0.0-1.0)
|
||||
|
||||
// Rendering
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// debris_manager.cpp - Implementació del gestor de fragments
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "debris_manager.hpp"
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
|
||||
namespace Effects {
|
||||
|
||||
// Helper: transformar point amb rotació, scale i trasllació
|
||||
// Helper: transformar point con rotación, scale i traslación
|
||||
// (Copiat de shape_renderer.cpp:12-34)
|
||||
static Vec2 transform_point(const Vec2& point, const Vec2& shape_centre, const Vec2& position, float angle, float scale) {
|
||||
// 1. Centrar el point respecte al centre de la shape
|
||||
// 1. Centrar el point respecte al centro de la shape
|
||||
float centered_x = point.x - shape_centre.x;
|
||||
float centered_y = point.y - shape_centre.y;
|
||||
|
||||
@@ -25,27 +25,27 @@ static Vec2 transform_point(const Vec2& point, const Vec2& shape_centre, const V
|
||||
float scaled_x = centered_x * scale;
|
||||
float scaled_y = centered_y * scale;
|
||||
|
||||
// 3. Aplicar rotació
|
||||
// 3. Aplicar rotación
|
||||
float cos_a = std::cos(angle);
|
||||
float sin_a = std::sin(angle);
|
||||
|
||||
float rotated_x = (scaled_x * cos_a) - (scaled_y * sin_a);
|
||||
float rotated_y = (scaled_x * sin_a) + (scaled_y * cos_a);
|
||||
|
||||
// 4. Aplicar trasllació a posició mundial
|
||||
// 4. Aplicar traslación a posición mundial
|
||||
return {.x = rotated_x + position.x, .y = rotated_y + position.y};
|
||||
}
|
||||
|
||||
DebrisManager::DebrisManager(SDL_Renderer* renderer)
|
||||
: renderer_(renderer) {
|
||||
// Inicialitzar tots els debris com inactius
|
||||
// Inicialitzar todos los debris como inactius
|
||||
for (auto& debris : debris_pool_) {
|
||||
debris.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
void DebrisManager::explode(const std::shared_ptr<Graphics::Shape>& shape,
|
||||
const Vec2& centre,
|
||||
const Vec2& centro,
|
||||
float angle,
|
||||
float scale,
|
||||
float velocitat_base,
|
||||
@@ -61,10 +61,10 @@ void DebrisManager::explode(const std::shared_ptr<Graphics::Shape>& shape,
|
||||
// Reproducir sonido de explosión
|
||||
Audio::get()->playSound(sound, Audio::Group::GAME);
|
||||
|
||||
// Obtenir centre de la shape per a transformacions
|
||||
// Obtenir centro de la shape para transformacions
|
||||
const Vec2& shape_centre = shape->getCenter();
|
||||
|
||||
// Iterar sobre totes les primitives de la shape
|
||||
// Iterar sobre todas las primitives de la shape
|
||||
for (const auto& primitive : shape->get_primitives()) {
|
||||
// Processar cada segment de línia
|
||||
std::vector<std::pair<Vec2, Vec2>> segments;
|
||||
@@ -81,13 +81,13 @@ void DebrisManager::explode(const std::shared_ptr<Graphics::Shape>& shape,
|
||||
}
|
||||
}
|
||||
|
||||
// Crear debris per a cada segment
|
||||
// Crear debris para cada segment
|
||||
for (const auto& [local_p1, local_p2] : segments) {
|
||||
// 1. Transformar points locals → coordenades mundials
|
||||
Vec2 world_p1 =
|
||||
transform_point(local_p1, shape_centre, centre, angle, scale);
|
||||
transform_point(local_p1, shape_centre, centro, angle, scale);
|
||||
Vec2 world_p2 =
|
||||
transform_point(local_p2, shape_centre, centre, angle, scale);
|
||||
transform_point(local_p2, shape_centre, centro, angle, scale);
|
||||
|
||||
// 2. Trobar slot lliure
|
||||
Debris* debris = findFreeSlot();
|
||||
@@ -100,10 +100,10 @@ void DebrisManager::explode(const std::shared_ptr<Graphics::Shape>& shape,
|
||||
debris->p1 = world_p1;
|
||||
debris->p2 = world_p2;
|
||||
|
||||
// 4. Calcular direcció d'explosió (radial, des del centre cap a fora)
|
||||
Vec2 direccio = computeExplosionDirection(world_p1, world_p2, centre);
|
||||
// 4. Calcular direcció de explosión (radial, des del centro hacia fuera)
|
||||
Vec2 direccio = computeExplosionDirection(world_p1, world_p2, centro);
|
||||
|
||||
// 5. Velocitat inicial (base ± variació aleatòria + velocity heretada)
|
||||
// 5. Velocidad inicial (base ± variació aleatòria + velocity heretada)
|
||||
float speed =
|
||||
velocitat_base +
|
||||
(((std::rand() / static_cast<float>(RAND_MAX)) * 2.0F - 1.0F) *
|
||||
@@ -114,11 +114,11 @@ void DebrisManager::explode(const std::shared_ptr<Graphics::Shape>& shape,
|
||||
debris->velocity.y = (direccio.y * speed) + velocitat_objecte.y;
|
||||
debris->acceleration = Defaults::Physics::Debris::ACCELERACIO;
|
||||
|
||||
// 6. Herència de velocity angular amb cap + conversió d'excés
|
||||
// 6. Herència de velocity angular con sin + conversió de excés
|
||||
|
||||
// 6a. Rotació de TRAYECTORIA amb cap + conversió tangencial
|
||||
// 6a. Rotación de TRAYECTORIA con sin + conversió tangencial
|
||||
if (std::abs(velocitat_angular) > 0.01F) {
|
||||
// FASE 1: Aplicar herència i variació (igual que abans)
|
||||
// FASE 1: Aplicar herència i variació (igual que antes)
|
||||
float factor_herencia =
|
||||
Defaults::Physics::Debris::FACTOR_HERENCIA_MIN +
|
||||
((std::rand() / static_cast<float>(RAND_MAX)) *
|
||||
@@ -131,7 +131,7 @@ void DebrisManager::explode(const std::shared_ptr<Graphics::Shape>& shape,
|
||||
((std::rand() / static_cast<float>(RAND_MAX)) * 0.2F) - 0.1F;
|
||||
velocitat_ang_heretada *= (1.0F + variacio);
|
||||
|
||||
// FASE 2: Aplicar cap i calcular excés
|
||||
// FASE 2: Aplicar sin i calcular excés
|
||||
constexpr float CAP = Defaults::Physics::Debris::VELOCITAT_ROT_MAX;
|
||||
float abs_ang = std::abs(velocitat_ang_heretada);
|
||||
float sign_ang = (velocitat_ang_heretada >= 0.0F) ? 1.0F : -1.0F;
|
||||
@@ -140,10 +140,10 @@ void DebrisManager::explode(const std::shared_ptr<Graphics::Shape>& shape,
|
||||
// Excés: convertir a velocity tangencial
|
||||
float excess = abs_ang - CAP;
|
||||
|
||||
// Radi de la shape (enemics = 20 px)
|
||||
// Radi de la shape (enemigos = 20 px)
|
||||
float radius = 20.0F;
|
||||
|
||||
// Velocitat tangencial = ω_excés × radi
|
||||
// Velocidad tangencial = ω_excés × radi
|
||||
float v_tangential = excess * radius;
|
||||
|
||||
// Direcció tangencial: perpendicular a la radial (90° CCW)
|
||||
@@ -151,38 +151,38 @@ void DebrisManager::explode(const std::shared_ptr<Graphics::Shape>& shape,
|
||||
float tangent_x = -direccio.y;
|
||||
float tangent_y = direccio.x;
|
||||
|
||||
// Afegir velocity tangencial (suma vectorial)
|
||||
// Añadir velocity tangencial (suma vectorial)
|
||||
debris->velocity.x += tangent_x * v_tangential;
|
||||
debris->velocity.y += tangent_y * v_tangential;
|
||||
|
||||
// Aplicar cap a velocity angular (preservar signe)
|
||||
// Aplicar hacia velocity angular (preservar signe)
|
||||
debris->velocitat_rot = sign_ang * CAP;
|
||||
} else {
|
||||
// Per sota del cap: comportament normal
|
||||
// Per sota del sin: comportament normal
|
||||
debris->velocitat_rot = velocitat_ang_heretada;
|
||||
}
|
||||
} else {
|
||||
debris->velocitat_rot = 0.0F; // Nave: sin curvas
|
||||
}
|
||||
|
||||
// 6b. Rotació VISUAL (proporcional según factor_herencia_visual)
|
||||
// 6b. Rotación VISUAL (proporcional según factor_herencia_visual)
|
||||
if (factor_herencia_visual > 0.01F && std::abs(velocitat_angular) > 0.01F) {
|
||||
// Heredar rotación visual con factor proporcional
|
||||
debris->velocitat_rot_visual = debris->velocitat_rot * factor_herencia_visual;
|
||||
|
||||
// Variació aleatòria petita (±5%) per naturalitat
|
||||
// Variació aleatòria pequeña (±5%) per naturalitat
|
||||
float variacio_visual =
|
||||
((std::rand() / static_cast<float>(RAND_MAX)) * 0.1F) - 0.05F;
|
||||
debris->velocitat_rot_visual *= (1.0F + variacio_visual);
|
||||
} else {
|
||||
// Rotació visual aleatòria (factor = 0.0 o sin velocidad angular)
|
||||
// Rotación visual aleatòria (factor = 0.0 o sin velocidad angular)
|
||||
debris->velocitat_rot_visual =
|
||||
Defaults::Physics::Debris::ROTACIO_MIN +
|
||||
((std::rand() / static_cast<float>(RAND_MAX)) *
|
||||
(Defaults::Physics::Debris::ROTACIO_MAX -
|
||||
Defaults::Physics::Debris::ROTACIO_MIN));
|
||||
|
||||
// 50% probabilitat de rotació en sentit contrari
|
||||
// 50% probabilitat de rotación en sentit contrari
|
||||
if (std::rand() % 2 == 0) {
|
||||
debris->velocitat_rot_visual = -debris->velocitat_rot_visual;
|
||||
}
|
||||
@@ -220,7 +220,7 @@ void DebrisManager::update(float delta_time) {
|
||||
}
|
||||
|
||||
// 2. Actualitzar velocity (desacceleració)
|
||||
// Aplicar fricció en la direcció del moviment
|
||||
// Aplicar fricció en la direcció del movement
|
||||
float speed = std::sqrt((debris.velocity.x * debris.velocity.x) +
|
||||
(debris.velocity.y * debris.velocity.y));
|
||||
|
||||
@@ -229,24 +229,24 @@ void DebrisManager::update(float delta_time) {
|
||||
float dir_x = debris.velocity.x / speed;
|
||||
float dir_y = debris.velocity.y / speed;
|
||||
|
||||
// Aplicar acceleració negativa (fricció)
|
||||
// Aplicar aceleración negativa (fricció)
|
||||
float nova_speed = speed + (debris.acceleration * delta_time);
|
||||
nova_speed = std::max(nova_speed, 0.0F);
|
||||
|
||||
debris.velocity.x = dir_x * nova_speed;
|
||||
debris.velocity.y = dir_y * nova_speed;
|
||||
} else {
|
||||
// Velocitat molt baixa, aturar
|
||||
// Velocidad mucho baixa, aturar
|
||||
debris.velocity.x = 0.0F;
|
||||
debris.velocity.y = 0.0F;
|
||||
}
|
||||
|
||||
// 2b. Rotar vector de velocity (trayectoria curva)
|
||||
if (std::abs(debris.velocitat_rot) > 0.01F) {
|
||||
// Calcular angle de rotació aquest frame
|
||||
// Calcular angle de rotación este frame
|
||||
float dangle = debris.velocitat_rot * delta_time;
|
||||
|
||||
// Rotar vector de velocity usant matriu de rotació 2D
|
||||
// Rotar vector de velocity usant matriu de rotación 2D
|
||||
float vel_x_old = debris.velocity.x;
|
||||
float vel_y_old = debris.velocity.y;
|
||||
|
||||
@@ -270,35 +270,35 @@ void DebrisManager::update(float delta_time) {
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Calcular centre del segment
|
||||
Vec2 centre = {.x = (debris.p1.x + debris.p2.x) / 2.0F,
|
||||
// 3. Calcular centro del segment
|
||||
Vec2 centro = {.x = (debris.p1.x + debris.p2.x) / 2.0F,
|
||||
.y = (debris.p1.y + debris.p2.y) / 2.0F};
|
||||
|
||||
// 4. Actualitzar posició del centre
|
||||
centre.x += debris.velocity.x * delta_time;
|
||||
centre.y += debris.velocity.y * delta_time;
|
||||
// 4. Actualitzar posición del centro
|
||||
centro.x += debris.velocity.x * delta_time;
|
||||
centro.y += debris.velocity.y * delta_time;
|
||||
|
||||
// 5. Actualitzar rotació VISUAL
|
||||
// 5. Actualitzar rotación VISUAL
|
||||
debris.angle_rotacio += debris.velocitat_rot_visual * delta_time;
|
||||
|
||||
// 6. Aplicar shrinking (reducció de distància entre points)
|
||||
// 6. Aplicar shrinking (reducció de distancia entre points)
|
||||
float shrink_factor =
|
||||
1.0F - (debris.factor_shrink * debris.temps_vida / debris.temps_max);
|
||||
shrink_factor = std::max(0.0F, shrink_factor); // No negatiu
|
||||
|
||||
// Calcular distància original entre points
|
||||
// Calcular distancia original entre points
|
||||
float dx = debris.p2.x - debris.p1.x;
|
||||
float dy = debris.p2.y - debris.p1.y;
|
||||
|
||||
// 7. Reconstruir segment amb nova mida i rotació
|
||||
// 7. Reconstruir segment con nueva mida i rotación
|
||||
float half_length = std::sqrt((dx * dx) + (dy * dy)) * shrink_factor / 2.0F;
|
||||
float original_angle = std::atan2(dy, dx);
|
||||
float new_angle = original_angle + debris.angle_rotacio;
|
||||
|
||||
debris.p1.x = centre.x - (half_length * std::cos(new_angle));
|
||||
debris.p1.y = centre.y - (half_length * std::sin(new_angle));
|
||||
debris.p2.x = centre.x + (half_length * std::cos(new_angle));
|
||||
debris.p2.y = centre.y + (half_length * std::sin(new_angle));
|
||||
debris.p1.x = centro.x - (half_length * std::cos(new_angle));
|
||||
debris.p1.y = centro.y - (half_length * std::sin(new_angle));
|
||||
debris.p2.x = centro.x + (half_length * std::cos(new_angle));
|
||||
debris.p2.y = centro.y + (half_length * std::sin(new_angle));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ void DebrisManager::draw() const {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Dibuixar segment de línia amb brightness heretat
|
||||
// Dibuixar segment de línia con brightness heretat
|
||||
Rendering::linea(renderer_,
|
||||
static_cast<int>(debris.p1.x),
|
||||
static_cast<int>(debris.p1.y),
|
||||
@@ -330,19 +330,19 @@ Debris* DebrisManager::findFreeSlot() {
|
||||
Vec2 DebrisManager::computeExplosionDirection(const Vec2& p1,
|
||||
const Vec2& p2,
|
||||
const Vec2& centre_objecte) const {
|
||||
// 1. Calcular centre del segment
|
||||
// 1. Calcular centro del segment
|
||||
float centro_seg_x = (p1.x + p2.x) / 2.0F;
|
||||
float centro_seg_y = (p1.y + p2.y) / 2.0F;
|
||||
|
||||
// 2. Calcular vector des del centre de l'objecte cap al centre del segment
|
||||
// Això garanteix que la direcció sempre apunte cap a fora (direcció radial)
|
||||
// 2. Calcular vector des del centro de l'objecte hacia el centro del segment
|
||||
// Això garanteix que la direcció siempre apunte hacia fuera (direcció radial)
|
||||
float dx = centro_seg_x - centre_objecte.x;
|
||||
float dy = centro_seg_y - centre_objecte.y;
|
||||
|
||||
// 3. Normalitzar (obtenir vector unitari)
|
||||
float length = std::sqrt((dx * dx) + (dy * dy));
|
||||
if (length < 0.001F) {
|
||||
// Segment al centre (cas extrem molt improbable), retornar direcció aleatòria
|
||||
// Segment al centro (cas extrem mucho improbable), retornar direcció aleatòria
|
||||
float angle_rand =
|
||||
(std::rand() / static_cast<float>(RAND_MAX)) * 2.0F * Defaults::Math::PI;
|
||||
return {.x = std::cos(angle_rand), .y = std::sin(angle_rand)};
|
||||
@@ -351,7 +351,7 @@ Vec2 DebrisManager::computeExplosionDirection(const Vec2& p1,
|
||||
dx /= length;
|
||||
dy /= length;
|
||||
|
||||
// 4. Afegir variació aleatòria petita (±15°) per varietat visual
|
||||
// 4. Añadir variació aleatòria pequeña (±15°) per varietat visual
|
||||
float angle_variacio =
|
||||
((std::rand() % 30) - 15) * Defaults::Math::PI / 180.0F;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// debris_manager.hpp - Gestor de fragments d'explosions
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// debris_manager.hpp - Gestor de fragments de explosions
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
#include <SDL3/SDL.h>
|
||||
@@ -14,24 +14,24 @@
|
||||
|
||||
namespace Effects {
|
||||
|
||||
// Gestor de fragments d'explosions
|
||||
// Manté un pool d'objectes Debris i gestiona el seu cicle de vida
|
||||
// Gestor de fragments de explosions
|
||||
// Manté un pool de objectes Debris i gestiona el seu cicle de vida
|
||||
class DebrisManager {
|
||||
public:
|
||||
explicit DebrisManager(SDL_Renderer* renderer);
|
||||
|
||||
// Crear explosió a partir d'una shape
|
||||
// Crear explosión a partir de una shape
|
||||
// - shape: shape vectorial a explode
|
||||
// - centre: posició del centre de l'objecte
|
||||
// - centro: posición del centro de l'objecte
|
||||
// - angle: orientació de l'objecte (radians)
|
||||
// - scale: scale de l'objecte (1.0 = normal)
|
||||
// - velocitat_base: velocity inicial dels fragments (px/s)
|
||||
// - brightness: factor de brightness heretat (0.0-1.0, per defecte 1.0)
|
||||
// - velocitat_objecte: velocity de l'objecte que explota (px/s, per defecte 0)
|
||||
// - velocitat_angular: velocity angular heretada (rad/s, per defecte 0)
|
||||
// - factor_herencia_visual: factor de herència rotació visual (0.0-1.0, per defecte 0.0)
|
||||
// - factor_herencia_visual: factor de herència rotación visual (0.0-1.0, per defecte 0.0)
|
||||
void explode(const std::shared_ptr<Graphics::Shape>& shape,
|
||||
const Vec2& centre,
|
||||
const Vec2& centro,
|
||||
float angle,
|
||||
float scale,
|
||||
float velocitat_base,
|
||||
@@ -41,13 +41,13 @@ class DebrisManager {
|
||||
float factor_herencia_visual = 0.0F,
|
||||
const std::string& sound = Defaults::Sound::EXPLOSION);
|
||||
|
||||
// Actualitzar tots els fragments active
|
||||
// Actualitzar todos los fragments active
|
||||
void update(float delta_time);
|
||||
|
||||
// Dibuixar tots els fragments active
|
||||
// Dibuixar todos los fragments active
|
||||
void draw() const;
|
||||
|
||||
// Reiniciar tots els fragments (neteja)
|
||||
// Reiniciar todos los fragments (clear)
|
||||
void reset();
|
||||
|
||||
// Obtenir número de fragments active
|
||||
@@ -57,8 +57,8 @@ class DebrisManager {
|
||||
SDL_Renderer* renderer_;
|
||||
|
||||
// Pool de fragments (màxim concurrent)
|
||||
// Un pentàgon té 5 línies, 15 enemics = 75 línies
|
||||
// + ship (3 línies) + bales (5 línies * 3) = 93 línies màxim
|
||||
// Un pentágono té 5 línies, 15 enemigos = 75 línies
|
||||
// + ship (3 línies) + balas (5 línies * 3) = 93 línies màxim
|
||||
// Arrodonit a 100 per seguretat
|
||||
static constexpr int MAX_DEBRIS = 150;
|
||||
std::array<Debris, MAX_DEBRIS> debris_pool_;
|
||||
@@ -66,7 +66,7 @@ class DebrisManager {
|
||||
// Trobar primer slot inactiu
|
||||
Debris* findFreeSlot();
|
||||
|
||||
// Calcular direcció d'explosió (radial, des del centre cap al segment)
|
||||
// Calcular direcció de explosión (radial, des del centro hacia el segment)
|
||||
[[nodiscard]] Vec2 computeExplosionDirection(const Vec2& p1, const Vec2& p2, const Vec2& centre_objecte) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// puntuacio_flotant.hpp - Número de puntuació que apareix i desapareix
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// floating_score.hpp - Número de puntuación que apareix y desapareix
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -9,19 +9,19 @@
|
||||
|
||||
namespace Effects {
|
||||
|
||||
// FloatingScore: text animat que mostra points guanyats
|
||||
// S'activa quan es destrueix un enemy i s'esvaeix després d'un time
|
||||
// FloatingScore: text animat que muestra points guanyats
|
||||
// S'activa cuando es destrueix un enemy i s'esvaeix después de un time
|
||||
struct FloatingScore {
|
||||
// Text a mostrar (e.g., "100", "150", "200")
|
||||
std::string text;
|
||||
|
||||
// Posició actual (coordenades mundials)
|
||||
// Posición actual (coordenades mundials)
|
||||
Vec2 position;
|
||||
|
||||
// Animació de moviment
|
||||
Vec2 velocity; // px/s (normalment cap amunt: {0.0f, -30.0f})
|
||||
// Animación de movement
|
||||
Vec2 velocity; // px/s (normalment sin amunt: {0.0f, -30.0f})
|
||||
|
||||
// Animació de fade
|
||||
// Animación de fade
|
||||
float temps_vida; // Temps transcorregut (segons)
|
||||
float temps_max; // Temps de vida màxim (segons)
|
||||
float brightness; // Brillantor calculada (0.0-1.0)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// gestor_puntuacio_flotant.cpp - Implementació del gestor de números flotants
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// floating_score_manager.cpp - Implementació del gestor de números flotantes
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "floating_score_manager.hpp"
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Effects {
|
||||
|
||||
FloatingScoreManager::FloatingScoreManager(SDL_Renderer* renderer)
|
||||
: text_(renderer) {
|
||||
// Inicialitzar tots els slots com inactius
|
||||
// Inicialitzar todos los slots como inactius
|
||||
for (auto& pf : pool_) {
|
||||
pf.active = false;
|
||||
}
|
||||
@@ -22,7 +22,7 @@ void FloatingScoreManager::crear(int points, const Vec2& position) {
|
||||
return; // Pool ple (improbable)
|
||||
}
|
||||
|
||||
// 2. Inicialitzar puntuació flotant
|
||||
// 2. Inicialitzar puntuación flotante
|
||||
pf->text = std::to_string(points);
|
||||
pf->position = position;
|
||||
pf->velocity = {.x = Defaults::FloatingScore::VELOCITY_X,
|
||||
@@ -39,7 +39,7 @@ void FloatingScoreManager::update(float delta_time) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 1. Actualitzar posició (deriva cap amunt)
|
||||
// 1. Actualitzar posición (deriva sin amunt)
|
||||
pf.position.x += pf.velocity.x * delta_time;
|
||||
pf.position.y += pf.velocity.y * delta_time;
|
||||
|
||||
@@ -50,7 +50,7 @@ void FloatingScoreManager::update(float delta_time) {
|
||||
float progress = pf.temps_vida / pf.temps_max; // 0.0 → 1.0
|
||||
pf.brightness = 1.0F - progress; // 1.0 → 0.0
|
||||
|
||||
// 4. Desactivar quan acaba el time
|
||||
// 4. Desactivar cuando acaba el time
|
||||
if (pf.temps_vida >= pf.temps_max) {
|
||||
pf.active = false;
|
||||
}
|
||||
@@ -63,7 +63,7 @@ void FloatingScoreManager::draw() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Renderitzar centrat amb brightness (fade)
|
||||
// Renderizar centrat con brightness (fade)
|
||||
constexpr float scale = Defaults::FloatingScore::SCALE;
|
||||
constexpr float spacing = Defaults::FloatingScore::SPACING;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// gestor_puntuacio_flotant.hpp - Gestor de números de puntuació flotants
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// floating_score_manager.hpp - Gestor de números de puntuación flotantes
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -14,24 +14,24 @@
|
||||
|
||||
namespace Effects {
|
||||
|
||||
// Gestor de números de puntuació flotants
|
||||
// Gestor de números de puntuación flotantes
|
||||
// Manté un pool de FloatingScore i gestiona el seu cicle de vida
|
||||
class FloatingScoreManager {
|
||||
public:
|
||||
explicit FloatingScoreManager(SDL_Renderer* renderer);
|
||||
|
||||
// Crear número flotant
|
||||
// - points: valor numèric (100, 150, 200)
|
||||
// - position: on apareix (normalment centre d'enemy destruït)
|
||||
// Crear número flotante
|
||||
// - points: value numèric (100, 150, 200)
|
||||
// - position: on apareix (normalment centro de enemy destruït)
|
||||
void crear(int points, const Vec2& position);
|
||||
|
||||
// Actualitzar tots els números active
|
||||
// Actualitzar todos los números active
|
||||
void update(float delta_time);
|
||||
|
||||
// Dibuixar tots els números active
|
||||
// Dibuixar todos los números active
|
||||
void draw();
|
||||
|
||||
// Reiniciar tots (neteja)
|
||||
// Reiniciar tots (clear)
|
||||
void reset();
|
||||
|
||||
// Obtenir número active (debug)
|
||||
@@ -40,8 +40,8 @@ class FloatingScoreManager {
|
||||
private:
|
||||
Graphics::VectorText text_; // Sistema de text vectorial
|
||||
|
||||
// Pool de números flotants (màxim concurrent)
|
||||
// Màxim 15 enemics simultanis = màxim 15 números
|
||||
// Pool de números flotantes (màxim concurrent)
|
||||
// Màxim 15 enemigos simultanis = màxim 15 números
|
||||
static constexpr int MAX_PUNTUACIONS =
|
||||
Defaults::FloatingScore::MAX_CONCURRENT;
|
||||
std::array<FloatingScore, MAX_PUNTUACIONS> pool_;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// bullet.cpp - Implementació de projectils de la ship
|
||||
// © 1999 Visente i Sergi (versió Pascal)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// © 1999 Visente i Sergi (versión Pascal)
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "game/entities/bullet.hpp"
|
||||
|
||||
@@ -23,10 +23,10 @@ Bullet::Bullet(SDL_Renderer* renderer)
|
||||
esta_(false),
|
||||
owner_id_(0),
|
||||
grace_timer_(0.0F) {
|
||||
// [NUEVO] Brightness específic per bales
|
||||
// [NUEVO] Brightness específic per balas
|
||||
brightness_ = Defaults::Brightness::BALA;
|
||||
|
||||
// [NUEVO] Carregar shape compartida des de fitxer
|
||||
// [NUEVO] Carregar shape compartida desde file
|
||||
shape_ = Graphics::ShapeLoader::load("bullet.shp");
|
||||
|
||||
if (!shape_ || !shape_->isValid()) {
|
||||
@@ -50,7 +50,7 @@ void Bullet::disparar(const Vec2& position, float angle, uint8_t owner_id) {
|
||||
// Activar bullet
|
||||
esta_ = true;
|
||||
|
||||
// Posició inicial = centre de la ship
|
||||
// Posición inicial = centro de la ship
|
||||
center_.x = position.x;
|
||||
center_.y = position.y;
|
||||
|
||||
@@ -60,7 +60,7 @@ void Bullet::disparar(const Vec2& position, float angle, uint8_t owner_id) {
|
||||
// Almacenar propietario (0=P1, 1=P2)
|
||||
owner_id_ = owner_id;
|
||||
|
||||
// Velocitat alta (el joc Pascal original usava 7 px/frame)
|
||||
// Velocidad alta (el juego Pascal original usava 7 px/frame)
|
||||
// 7 px/frame × 20 FPS = 140 px/s
|
||||
velocity_ = 140.0F;
|
||||
|
||||
@@ -86,7 +86,7 @@ void Bullet::update(float delta_time) {
|
||||
void Bullet::draw() const {
|
||||
if (esta_ && shape_) {
|
||||
// [NUEVO] Usar render_shape en lloc de rota_pol
|
||||
// Les bales roten segons l'angle de trajectòria
|
||||
// Les balas roten segons l'angle de trajectòria
|
||||
Rendering::render_shape(renderer_, shape_, center_, angle_, 1.0F, 1.0F, brightness_);
|
||||
}
|
||||
}
|
||||
@@ -96,20 +96,20 @@ void Bullet::mou(float delta_time) {
|
||||
// Basat en el codi Pascal original: procedure mou_bales
|
||||
// Copiat EXACTAMENT de joc_asteroides.cpp línies 396-419
|
||||
|
||||
// Calcular nova posició (moviment polar time-based)
|
||||
// velocity ja està en px/s (140 px/s), només cal multiplicar per delta_time
|
||||
// Calcular nueva posición (movement polar time-based)
|
||||
// velocity ya está en px/s (140 px/s), solo necesario multiplicar per delta_time
|
||||
float velocitat_efectiva = velocity_ * delta_time;
|
||||
|
||||
// Calcular desplaçament (angle-PI/2 perquè angle=0 apunta amunt)
|
||||
float dy = velocitat_efectiva * std::sin(angle_ - (Constants::PI / 2.0F));
|
||||
float dx = velocitat_efectiva * std::cos(angle_ - (Constants::PI / 2.0F));
|
||||
|
||||
// Acumulació directa amb precisió subpíxel
|
||||
// Acumulació directa con precisió subpíxel
|
||||
center_.y += dy;
|
||||
center_.x += dx;
|
||||
|
||||
// Desactivar si surt de la zona de joc (no rebota com els ORNIs)
|
||||
// CORRECCIÓ: Usar límits segurs amb radi de la bullet
|
||||
// Desactivar si surt de la zona de juego (no rebota como los ORNIs)
|
||||
// CORRECCIÓ: Usar límits segurs con radi de la bullet
|
||||
float min_x;
|
||||
float max_x;
|
||||
float min_y;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// bullet.hpp - Classe per a projectils de la ship
|
||||
// © 1999 Visente i Sergi (versió Pascal)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// bullet.hpp - Clase para projectils de la ship
|
||||
// © 1999 Visente i Sergi (versión Pascal)
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
#include <SDL3/SDL.h>
|
||||
@@ -25,7 +25,7 @@ class Bullet : public Entities::Entity {
|
||||
// Override: Interfície d'Entity
|
||||
[[nodiscard]] bool isActive() const override { return esta_; }
|
||||
|
||||
// Override: Interfície de col·lisió
|
||||
// Override: Interfície de colisión
|
||||
[[nodiscard]] float getCollisionRadius() const override {
|
||||
return Defaults::Entities::BULLET_RADIUS;
|
||||
}
|
||||
@@ -33,7 +33,7 @@ class Bullet : public Entities::Entity {
|
||||
return esta_ && grace_timer_ <= 0.0F;
|
||||
}
|
||||
|
||||
// Getters (API pública sense canvis)
|
||||
// Getters (API pública sin canvis)
|
||||
[[nodiscard]] bool esta_activa() const { return esta_; }
|
||||
[[nodiscard]] uint8_t get_owner_id() const { return owner_id_; }
|
||||
[[nodiscard]] float get_grace_timer() const { return grace_timer_; }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// enemy.cpp - Implementació d'enemics (ORNIs)
|
||||
// © 1999 Visente i Sergi (versió Pascal)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// enemy.cpp - Implementació de enemigos (ORNIs)
|
||||
// © 1999 Visente i Sergi (versión Pascal)
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "game/entities/enemy.hpp"
|
||||
|
||||
@@ -27,7 +27,7 @@ Enemy::Enemy(SDL_Renderer* renderer)
|
||||
ship_position_(nullptr),
|
||||
tracking_strength_(0.5F), // Default tracking strength
|
||||
timer_invulnerabilitat_(0.0F) { // Start vulnerable
|
||||
// [NUEVO] Brightness específic per enemics
|
||||
// [NUEVO] Brightness específic per enemigos
|
||||
brightness_ = Defaults::Brightness::ENEMIC;
|
||||
|
||||
// [NUEVO] Forma es carrega a init() segons el type
|
||||
@@ -52,10 +52,10 @@ void Enemy::init(EnemyType type, const Vec2* ship_pos) {
|
||||
break;
|
||||
|
||||
case EnemyType::QUADRAT:
|
||||
shape_file = Defaults::Enemies::Quadrat::SHAPE_FILE;
|
||||
velocity_ = Defaults::Enemies::Quadrat::VELOCITAT;
|
||||
drotacio_min = Defaults::Enemies::Quadrat::DROTACIO_MIN;
|
||||
drotacio_max = Defaults::Enemies::Quadrat::DROTACIO_MAX;
|
||||
shape_file = Defaults::Enemies::Cuadrado::SHAPE_FILE;
|
||||
velocity_ = Defaults::Enemies::Cuadrado::VELOCITAT;
|
||||
drotacio_min = Defaults::Enemies::Cuadrado::DROTACIO_MIN;
|
||||
drotacio_max = Defaults::Enemies::Cuadrado::DROTACIO_MAX;
|
||||
tracking_timer_ = 0.0F;
|
||||
break;
|
||||
|
||||
@@ -83,7 +83,7 @@ void Enemy::init(EnemyType type, const Vec2* ship_pos) {
|
||||
std::cerr << "[Enemy] Error: no s'ha pogut load " << shape_file << '\n';
|
||||
}
|
||||
|
||||
// [MODIFIED] Posició aleatòria amb comprovació de seguretat
|
||||
// [MODIFIED] Posición aleatòria con comprobación de seguretat
|
||||
float min_x;
|
||||
float max_x;
|
||||
float min_y;
|
||||
@@ -117,7 +117,7 @@ void Enemy::init(EnemyType type, const Vec2* ship_pos) {
|
||||
center_.x = static_cast<float>((std::rand() % range_x) + static_cast<int>(min_x));
|
||||
center_.y = static_cast<float>((std::rand() % range_y) + static_cast<int>(min_y));
|
||||
|
||||
std::cout << "[Enemy] Advertència: spawn sense zona segura després de "
|
||||
std::cout << "[Enemy] Advertència: spawn sin zona segura después de "
|
||||
<< Defaults::Enemies::Spawn::MAX_SPAWN_ATTEMPTS << " intents" << '\n';
|
||||
}
|
||||
} else {
|
||||
@@ -128,15 +128,15 @@ void Enemy::init(EnemyType type, const Vec2* ship_pos) {
|
||||
center_.y = static_cast<float>((std::rand() % range_y) + static_cast<int>(min_y));
|
||||
}
|
||||
|
||||
// Angle aleatori de moviment
|
||||
// Angle aleatori de movement
|
||||
angle_ = (std::rand() % 360) * Constants::PI / 180.0F;
|
||||
|
||||
// Rotació visual aleatòria (rad/s) dins del rang del type
|
||||
// Rotación visual aleatòria (rad/s) dins del rang del type
|
||||
float drotacio_range = drotacio_max - drotacio_min;
|
||||
drotacio_ = drotacio_min + ((static_cast<float>(std::rand()) / RAND_MAX) * drotacio_range);
|
||||
rotacio_ = 0.0F;
|
||||
|
||||
// Inicialitzar state d'animació
|
||||
// Inicialitzar state de animación
|
||||
animacio_ = EnemyAnimation(); // Reset to defaults
|
||||
animacio_.drotacio_base = drotacio_;
|
||||
animacio_.drotacio_objetivo = drotacio_;
|
||||
@@ -171,10 +171,10 @@ void Enemy::update(float delta_time) {
|
||||
// Moviment autònom
|
||||
mou(delta_time);
|
||||
|
||||
// Actualitzar animacions (palpitació, rotació accelerada)
|
||||
// Actualitzar animaciones (palpitació, rotación accelerada)
|
||||
actualitzar_animacio(delta_time);
|
||||
|
||||
// Rotació visual (time-based: drotacio_ està en rad/s)
|
||||
// Rotación visual (time-based: drotacio_ está en rad/s)
|
||||
rotacio_ += drotacio_ * delta_time;
|
||||
}
|
||||
}
|
||||
@@ -210,7 +210,7 @@ void Enemy::mou(float delta_time) {
|
||||
|
||||
void Enemy::comportament_pentagon(float delta_time) {
|
||||
// Pentagon: zigzag esquivador (frequent direction changes)
|
||||
// Similar a comportament original però amb probabilitat més alta
|
||||
// Similar a comportament original pero con probabilitat més alta
|
||||
|
||||
float velocitat_efectiva = velocity_ * delta_time;
|
||||
|
||||
@@ -232,11 +232,11 @@ void Enemy::comportament_pentagon(float delta_time) {
|
||||
min_y,
|
||||
max_y);
|
||||
|
||||
// Zigzag: canvi d'angle més freqüent en tocar límits
|
||||
// Zigzag: canvi de angle més freqüent en tocar límits
|
||||
if (new_y >= min_y && new_y <= max_y) {
|
||||
center_.y = new_y;
|
||||
} else {
|
||||
// Probabilitat més alta de canvi d'angle
|
||||
// Probabilitat més alta de canvi de angle
|
||||
if (static_cast<float>(std::rand()) / RAND_MAX < Defaults::Enemies::Pentagon::CANVI_ANGLE_PROB) {
|
||||
float rand_angle = (static_cast<float>(std::rand()) / RAND_MAX) *
|
||||
Defaults::Enemies::Pentagon::CANVI_ANGLE_MAX;
|
||||
@@ -256,13 +256,13 @@ void Enemy::comportament_pentagon(float delta_time) {
|
||||
}
|
||||
|
||||
void Enemy::comportament_quadrat(float delta_time) {
|
||||
// Quadrat: perseguidor (tracks player position)
|
||||
// Cuadrado: perseguidor (tracks player position)
|
||||
|
||||
// Update tracking timer
|
||||
tracking_timer_ += delta_time;
|
||||
|
||||
// Periodically update angle toward ship
|
||||
if (tracking_timer_ >= Defaults::Enemies::Quadrat::TRACKING_INTERVAL) {
|
||||
if (tracking_timer_ >= Defaults::Enemies::Cuadrado::TRACKING_INTERVAL) {
|
||||
tracking_timer_ = 0.0F;
|
||||
|
||||
if (ship_position_ != nullptr) {
|
||||
@@ -488,7 +488,7 @@ float Enemy::calcular_escala_actual() const {
|
||||
constexpr float END = Defaults::Enemies::Spawn::INVULNERABILITY_SCALE_END;
|
||||
scale = START + ((END - START) * smooth_t);
|
||||
} else if (animacio_.palpitacio_activa) {
|
||||
// [EXISTING] Palpitació només quan no invulnerable
|
||||
// [EXISTING] Palpitació solo cuando no invulnerable
|
||||
scale += animacio_.palpitacio_amplitud * std::sin(animacio_.palpitacio_fase);
|
||||
}
|
||||
|
||||
@@ -502,7 +502,7 @@ float Enemy::get_base_velocity() const {
|
||||
case EnemyType::PENTAGON:
|
||||
return Defaults::Enemies::Pentagon::VELOCITAT;
|
||||
case EnemyType::QUADRAT:
|
||||
return Defaults::Enemies::Quadrat::VELOCITAT;
|
||||
return Defaults::Enemies::Cuadrado::VELOCITAT;
|
||||
case EnemyType::MOLINILLO:
|
||||
return Defaults::Enemies::Molinillo::VELOCITAT;
|
||||
default:
|
||||
@@ -544,8 +544,8 @@ bool Enemy::intent_spawn_safe(const Vec2& ship_pos, float& out_x, float& out_y)
|
||||
// Check Euclidean distance to ship
|
||||
float dx = out_x - ship_pos.x;
|
||||
float dy = out_y - ship_pos.y;
|
||||
float distancia = std::sqrt((dx * dx) + (dy * dy));
|
||||
float distance = std::sqrt((dx * dx) + (dy * dy));
|
||||
|
||||
// Return true if position is safe (>= 36px from ship)
|
||||
return distancia >= Defaults::Enemies::Spawn::SAFETY_DISTANCE;
|
||||
return distance >= Defaults::Enemies::Spawn::SAFETY_DISTANCE;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// enemy.hpp - Classe per a enemics (ORNIs pentàgons)
|
||||
// © 1999 Visente i Sergi (versió Pascal)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// enemy.hpp - Clase para enemigos (ORNIs pentágonos)
|
||||
// © 1999 Visente i Sergi (versión Pascal)
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
#include <SDL3/SDL.h>
|
||||
@@ -13,14 +13,14 @@
|
||||
#include "core/types.hpp"
|
||||
#include "game/constants.hpp"
|
||||
|
||||
// Tipus d'enemy
|
||||
// Tipo de enemy
|
||||
enum class EnemyType : uint8_t {
|
||||
PENTAGON = 0, // Pentàgon esquivador (zigzag)
|
||||
QUADRAT = 1, // Quadrat perseguidor (tracks ship)
|
||||
PENTAGON = 0, // Pentágono esquivador (zigzag)
|
||||
QUADRAT = 1, // Cuadrado perseguidor (tracks ship)
|
||||
MOLINILLO = 2 // Molinillo agressiu (fast, spinning)
|
||||
};
|
||||
|
||||
// Estat d'animació (palpitació i rotació accelerada)
|
||||
// Estat de animación (palpitació i rotación accelerada)
|
||||
struct EnemyAnimation {
|
||||
// Palpitation (breathing effect)
|
||||
bool palpitacio_activa = false;
|
||||
@@ -50,7 +50,7 @@ class Enemy : public Entities::Entity {
|
||||
// Override: Interfície d'Entity
|
||||
[[nodiscard]] bool isActive() const override { return esta_; }
|
||||
|
||||
// Override: Interfície de col·lisió
|
||||
// Override: Interfície de colisión
|
||||
[[nodiscard]] float getCollisionRadius() const override {
|
||||
return Defaults::Entities::ENEMY_RADIUS;
|
||||
}
|
||||
@@ -58,7 +58,7 @@ class Enemy : public Entities::Entity {
|
||||
return esta_ && timer_invulnerabilitat_ <= 0.0F;
|
||||
}
|
||||
|
||||
// Getters (API pública sense canvis)
|
||||
// Getters (API pública sin canvis)
|
||||
void destruir() { esta_ = false; }
|
||||
[[nodiscard]] float get_drotacio() const { return drotacio_; }
|
||||
[[nodiscard]] Vec2 getVelocityVector() const {
|
||||
@@ -90,8 +90,8 @@ class Enemy : public Entities::Entity {
|
||||
private:
|
||||
// Membres específics d'Enemy (heretats: renderer_, shape_, center_, angle_, brightness_)
|
||||
float velocity_;
|
||||
float drotacio_; // Delta rotació visual (rad/s)
|
||||
float rotacio_; // Rotació visual acumulada
|
||||
float drotacio_; // Delta rotación visual (rad/s)
|
||||
float rotacio_; // Rotación visual acumulada
|
||||
bool esta_;
|
||||
|
||||
// [NEW] Enemy type and configuration
|
||||
@@ -101,9 +101,9 @@ class Enemy : public Entities::Entity {
|
||||
EnemyAnimation animacio_;
|
||||
|
||||
// [NEW] Behavior state (type-specific)
|
||||
float tracking_timer_; // For Quadrat: time since last angle update
|
||||
float tracking_timer_; // For Cuadrado: time since last angle update
|
||||
const Vec2* ship_position_; // Pointer to ship position (for tracking)
|
||||
float tracking_strength_; // For Quadrat: tracking intensity (0.0-1.5), default 0.5
|
||||
float tracking_strength_; // For Cuadrado: tracking intensity (0.0-1.5), default 0.5
|
||||
|
||||
// [NEW] Invulnerability state
|
||||
float timer_invulnerabilitat_; // Countdown timer (seconds), 0.0f = vulnerable
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// ship.cpp - Implementació de la nave del player
|
||||
// © 1999 Visente i Sergi (versió Pascal)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// © 1999 Visente i Sergi (versión Pascal)
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "game/entities/ship.hpp"
|
||||
|
||||
@@ -25,10 +25,10 @@ Ship::Ship(SDL_Renderer* renderer, const char* shape_file)
|
||||
velocity_(0.0F),
|
||||
is_hit_(false),
|
||||
invulnerable_timer_(0.0F) {
|
||||
// [NUEVO] Brightness específic per naus
|
||||
// [NUEVO] Brightness específic per naves
|
||||
brightness_ = Defaults::Brightness::NAU;
|
||||
|
||||
// [NUEVO] Carregar shape compartida des de fitxer
|
||||
// [NUEVO] Carregar shape compartida desde file
|
||||
shape_ = Graphics::ShapeLoader::load(shape_file);
|
||||
|
||||
if (!shape_ || !shape_->isValid()) {
|
||||
@@ -37,12 +37,12 @@ Ship::Ship(SDL_Renderer* renderer, const char* shape_file)
|
||||
}
|
||||
|
||||
void Ship::init(const Vec2* spawn_point, bool activar_invulnerabilitat) {
|
||||
// Inicialització de la ship (triangle)
|
||||
// Inicialización de la ship (triangle)
|
||||
// Basat en el codi Pascal original: lines 380-384
|
||||
// Copiat de joc_asteroides.cpp línies 30-44
|
||||
|
||||
// [NUEVO] Ja no cal configurar points polars - la geometria es carrega del
|
||||
// fitxer Només inicialitzem l'state de la instància
|
||||
// [NUEVO] Ya no necesario configure points polars - la geometria es carrega del
|
||||
// file Solo inicialitzem l'state de la instància
|
||||
|
||||
// Use custom spawn point if provided, otherwise use center
|
||||
if (spawn_point != nullptr) {
|
||||
@@ -72,9 +72,9 @@ void Ship::init(const Vec2* spawn_point, bool activar_invulnerabilitat) {
|
||||
}
|
||||
|
||||
void Ship::processInput(float delta_time, uint8_t player_id) {
|
||||
// Processar input continu (com teclapuls() del Pascal original)
|
||||
// Processar input continu (como teclapuls() del Pascal original)
|
||||
// Basat en joc_asteroides.cpp línies 66-85
|
||||
// Només processa input si la ship està viva
|
||||
// Solo processa input si la ship está viva
|
||||
if (is_hit_) {
|
||||
return;
|
||||
}
|
||||
@@ -118,7 +118,7 @@ void Ship::processInput(float delta_time, uint8_t player_id) {
|
||||
}
|
||||
|
||||
void Ship::update(float delta_time) {
|
||||
// Només update si la ship està viva
|
||||
// Solo update si la ship está viva
|
||||
if (is_hit_) {
|
||||
return;
|
||||
}
|
||||
@@ -129,12 +129,12 @@ void Ship::update(float delta_time) {
|
||||
invulnerable_timer_ = std::max(invulnerable_timer_, 0.0F);
|
||||
}
|
||||
|
||||
// Aplicar física (moviment + fricció)
|
||||
// Aplicar física (movement + fricció)
|
||||
applyPhysics(delta_time);
|
||||
}
|
||||
|
||||
void Ship::draw() const {
|
||||
// Només draw si la ship està viva
|
||||
// Solo draw si la ship está viva
|
||||
if (is_hit_) {
|
||||
return;
|
||||
}
|
||||
@@ -156,9 +156,9 @@ void Ship::draw() const {
|
||||
return;
|
||||
}
|
||||
|
||||
// Escalar velocity per l'efecte visual (200 px/s → ~6 px d'efecte)
|
||||
// Escalar velocity per l'efecte visual (200 px/s → ~6 px de efecte)
|
||||
// El codi Pascal original sumava velocity (0-6) al radi per donar
|
||||
// sensació de "empenta". Ara velocity està en px/s (0-200).
|
||||
// sensació de "empenta". Ara velocity está en px/s (0-200).
|
||||
// Basat en joc_asteroides.cpp línies 127-134
|
||||
//
|
||||
// [NUEVO] Convertir suma de velocitat_visual a scale multiplicativa
|
||||
@@ -171,12 +171,12 @@ void Ship::draw() const {
|
||||
}
|
||||
|
||||
void Ship::applyPhysics(float delta_time) {
|
||||
// Aplicar física de moviment
|
||||
// Aplicar física de movement
|
||||
// Basat en joc_asteroides.cpp línies 87-113
|
||||
|
||||
// Calcular nova posició basada en velocity i angle
|
||||
// S'usa (angle - PI/2) perquè angle=0 apunta cap amunt, no cap a la dreta
|
||||
// velocity_ està en px/s, així que multipliquem per delta_time
|
||||
// Calcular nueva posición basada en velocity i angle
|
||||
// S'usa (angle - PI/2) perquè angle=0 apunta sin amunt, no hacia la derecha
|
||||
// velocity_ está en px/s, así que multipliquem per delta_time
|
||||
float dy =
|
||||
((velocity_ * delta_time) * std::sin(angle_ - (Constants::PI / 2.0F))) +
|
||||
center_.y;
|
||||
@@ -184,7 +184,7 @@ void Ship::applyPhysics(float delta_time) {
|
||||
((velocity_ * delta_time) * std::cos(angle_ - (Constants::PI / 2.0F))) +
|
||||
center_.x;
|
||||
|
||||
// Boundary checking amb radi de la ship
|
||||
// Boundary checking con radi de la ship
|
||||
// CORRECCIÓ: Usar límits segurs i inequalitats inclusives
|
||||
float min_x;
|
||||
float max_x;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// ship.hpp - Classe per a la nave del player
|
||||
// © 1999 Visente i Sergi (versió Pascal)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// ship.hpp - Clase para la nave del player
|
||||
// © 1999 Visente i Sergi (versión Pascal)
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
#include <SDL3/SDL.h>
|
||||
@@ -28,7 +28,7 @@ class Ship : public Entities::Entity {
|
||||
// Override: Interfície d'Entity
|
||||
[[nodiscard]] bool isActive() const override { return !is_hit_; }
|
||||
|
||||
// Override: Interfície de col·lisió
|
||||
// Override: Interfície de colisión
|
||||
[[nodiscard]] float getCollisionRadius() const override {
|
||||
return Defaults::Entities::SHIP_RADIUS;
|
||||
}
|
||||
@@ -36,7 +36,7 @@ class Ship : public Entities::Entity {
|
||||
return !is_hit_ && invulnerable_timer_ <= 0.0F;
|
||||
}
|
||||
|
||||
// Getters (API pública sense canvis)
|
||||
// Getters (API pública sin canvis)
|
||||
[[nodiscard]] bool isAlive() const { return !is_hit_; }
|
||||
[[nodiscard]] bool isHit() const { return is_hit_; }
|
||||
[[nodiscard]] bool isInvulnerable() const { return invulnerable_timer_ > 0.0F; }
|
||||
@@ -49,12 +49,12 @@ class Ship : public Entities::Entity {
|
||||
// Setters
|
||||
void setCenter(const Vec2& nou_centre) { center_ = nou_centre; }
|
||||
|
||||
// Col·lisions (Fase 10)
|
||||
// Colisiones (Fase 10)
|
||||
void markHit() { is_hit_ = true; }
|
||||
|
||||
private:
|
||||
// Membres específics de Ship (heretats: renderer_, shape_, center_, angle_, brightness_)
|
||||
float velocity_; // Velocitat (px/s)
|
||||
float velocity_; // Velocidad (px/s)
|
||||
bool is_hit_;
|
||||
float invulnerable_timer_; // 0.0f = vulnerable, >0.0f = invulnerable
|
||||
|
||||
|
||||
+21
-21
@@ -135,8 +135,8 @@ static const std::unordered_map<int, std::string> BUTTON_TO_STRING = {
|
||||
{SDL_GAMEPAD_BUTTON_DPAD_DOWN, "DPAD_DOWN"},
|
||||
{SDL_GAMEPAD_BUTTON_DPAD_LEFT, "DPAD_LEFT"},
|
||||
{SDL_GAMEPAD_BUTTON_DPAD_RIGHT, "DPAD_RIGHT"},
|
||||
{100, "L2_AS_BUTTON"}, // Trigger L2 com a botó digital
|
||||
{101, "R2_AS_BUTTON"} // Trigger R2 com a botó digital
|
||||
{100, "L2_AS_BUTTON"}, // Trigger L2 como a botó digital
|
||||
{101, "R2_AS_BUTTON"} // Trigger R2 como a botó digital
|
||||
};
|
||||
|
||||
// Mapa invers: string a botó de gamepad
|
||||
@@ -178,7 +178,7 @@ static auto stringToButton(const std::string& str) -> int {
|
||||
|
||||
// ========== FI FUNCIONS AUXILIARS ==========
|
||||
|
||||
// Inicialitzar opcions amb valors per defecte de Defaults::
|
||||
// Inicialitzar opciones con valors per defecte de Defaults::
|
||||
void init() {
|
||||
#ifdef _DEBUG
|
||||
console = true;
|
||||
@@ -219,10 +219,10 @@ void init() {
|
||||
version = std::string(Project::VERSION);
|
||||
}
|
||||
|
||||
// Establir la ruta del fitxer de configuració
|
||||
// Establir la ruta del file de configuración
|
||||
void setConfigFile(const std::string& path) { config_file_path = path; }
|
||||
|
||||
// Funcions auxiliars per load seccions del YAML
|
||||
// Funciones auxiliars per load seccions del YAML
|
||||
|
||||
static void loadWindowConfigFromYaml(const fkyaml::node& yaml) {
|
||||
if (yaml.contains("window")) {
|
||||
@@ -372,7 +372,7 @@ static void loadRenderingConfigFromYaml(const fkyaml::node& yaml) {
|
||||
if (rend.contains("vsync")) {
|
||||
try {
|
||||
int val = rend["vsync"].get_value<int>();
|
||||
// Validar: només 0 o 1
|
||||
// Validar: solo 0 o 1
|
||||
rendering.vsync = (val == 0 || val == 1) ? val : Defaults::Rendering::VSYNC_DEFAULT;
|
||||
} catch (...) {
|
||||
rendering.vsync = Defaults::Rendering::VSYNC_DEFAULT;
|
||||
@@ -446,7 +446,7 @@ static void loadAudioConfigFromYaml(const fkyaml::node& yaml) {
|
||||
}
|
||||
}
|
||||
|
||||
// Carregar controls del player 1 des de YAML
|
||||
// Carregar controls del player 1 desde YAML
|
||||
static void loadPlayer1ControlsFromYaml(const fkyaml::node& yaml) {
|
||||
if (!yaml.contains("player1")) {
|
||||
return;
|
||||
@@ -494,7 +494,7 @@ static void loadPlayer1ControlsFromYaml(const fkyaml::node& yaml) {
|
||||
}
|
||||
}
|
||||
|
||||
// Carregar controls del player 2 des de YAML
|
||||
// Carregar controls del player 2 desde YAML
|
||||
static void loadPlayer2ControlsFromYaml(const fkyaml::node& yaml) {
|
||||
if (!yaml.contains("player2")) {
|
||||
return;
|
||||
@@ -542,22 +542,22 @@ static void loadPlayer2ControlsFromYaml(const fkyaml::node& yaml) {
|
||||
}
|
||||
}
|
||||
|
||||
// Carregar configuració des del fitxer YAML
|
||||
// Carregar configuración des del file YAML
|
||||
auto loadFromFile() -> bool {
|
||||
const std::string CONFIG_VERSION = std::string(Project::VERSION);
|
||||
|
||||
std::ifstream file(config_file_path);
|
||||
if (!file.good()) {
|
||||
// El fitxer no existeix → crear-ne un de nou amb valors per defecte
|
||||
// El file no existeix → crear-ne un de nuevo con valors per defecte
|
||||
if (console) {
|
||||
std::cout << "Fitxer de config no trobat, creant-ne un de nou: "
|
||||
std::cout << "Archivo de config no trobat, creant-ne un de nuevo: "
|
||||
<< config_file_path << '\n';
|
||||
}
|
||||
saveToFile();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Llegir tot el contingut del fitxer
|
||||
// Llegir todo el contingut del file
|
||||
std::string content((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
file.close();
|
||||
@@ -566,15 +566,15 @@ auto loadFromFile() -> bool {
|
||||
// Parsejar YAML
|
||||
auto yaml = fkyaml::node::deserialize(content);
|
||||
|
||||
// Validar versió
|
||||
// Validar versión
|
||||
if (yaml.contains("version")) {
|
||||
version = yaml["version"].get_value<std::string>();
|
||||
}
|
||||
|
||||
if (CONFIG_VERSION != version) {
|
||||
// Versió incompatible → regenerar config
|
||||
// Versión incompatible → regenerar config
|
||||
if (console) {
|
||||
std::cout << "Versió de config incompatible (esperada: "
|
||||
std::cout << "Versión de config incompatible (esperada: "
|
||||
<< CONFIG_VERSION << ", trobada: " << version
|
||||
<< "), regenerant config\n";
|
||||
}
|
||||
@@ -593,7 +593,7 @@ auto loadFromFile() -> bool {
|
||||
loadPlayer2ControlsFromYaml(yaml);
|
||||
|
||||
if (console) {
|
||||
std::cout << "Config carregada correctament des de: " << config_file_path
|
||||
std::cout << "Config carregada correctament desde: " << config_file_path
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
@@ -603,7 +603,7 @@ auto loadFromFile() -> bool {
|
||||
// Error de parsejat YAML → regenerar config
|
||||
if (console) {
|
||||
std::cerr << "Error parsejant YAML: " << e.what() << '\n';
|
||||
std::cerr << "Creant config nou amb valors per defecte\n";
|
||||
std::cerr << "Creant config nuevo con valors per defecte\n";
|
||||
}
|
||||
init();
|
||||
saveToFile();
|
||||
@@ -645,19 +645,19 @@ static void savePlayer2ControlsToYaml(std::ofstream& file) {
|
||||
file << " gamepad_name: \"" << player2.gamepad_name << "\" # Buit = segon disponible\n\n";
|
||||
}
|
||||
|
||||
// Guardar configuració al fitxer YAML
|
||||
// Guardar configuración al file YAML
|
||||
auto saveToFile() -> bool {
|
||||
std::ofstream file(config_file_path);
|
||||
if (!file.is_open()) {
|
||||
if (console) {
|
||||
std::cerr << "No s'ha pogut obrir el fitxer de config per escriure: "
|
||||
std::cerr << "No s'ha pogut obrir el file de config per escriure: "
|
||||
<< config_file_path << '\n';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Escriure manualment per controlar format i comentaris
|
||||
file << "# Orni Attack - Fitxer de Configuració\n";
|
||||
file << "# Orni Attack - Archivo de Configuración\n";
|
||||
file << "# Auto-generat. Les edicions manuals es preserven si són "
|
||||
"vàlides.\n\n";
|
||||
|
||||
@@ -670,7 +670,7 @@ auto saveToFile() -> bool {
|
||||
file << " fullscreen: " << (window.fullscreen ? "true" : "false") << "\n";
|
||||
file << " zoom_factor: " << window.zoom_factor << " # 0.5x-max (0.1 increments)\n\n";
|
||||
|
||||
file << "# FÍSICA (tots els valors en px/s, rad/s, etc.)\n";
|
||||
file << "# FÍSICA (todos los valors en px/s, rad/s, etc.)\n";
|
||||
file << "physics:\n";
|
||||
file << " rotation_speed: " << physics.rotation_speed << " # rad/s\n";
|
||||
file << " acceleration: " << physics.acceleration << " # px/s²\n";
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace Options {
|
||||
|
||||
// Estructures de configuració
|
||||
// Estructures de configuración
|
||||
|
||||
struct Window {
|
||||
int width{640};
|
||||
@@ -75,7 +75,7 @@ struct PlayerControls {
|
||||
|
||||
// Variables globals (inline per evitar ODR violations)
|
||||
|
||||
inline std::string version{}; // Versió del config per validació
|
||||
inline std::string version{}; // Versión del config per validació
|
||||
inline bool console{false}; // Eixida de debug
|
||||
inline Window window{};
|
||||
inline Physics physics{};
|
||||
@@ -104,17 +104,17 @@ inline PlayerControls player2{
|
||||
.gamepad_name = "" // Segon gamepad disponible
|
||||
};
|
||||
|
||||
// Per compatibilitat amb pollo (no utilitzat en orni, però necessari per Input)
|
||||
// Per compatibilitat con pollo (no utilitzat en orni, pero necessari per Input)
|
||||
inline KeyboardControls keyboard_controls{};
|
||||
inline GamepadControls gamepad_controls{};
|
||||
|
||||
inline std::string config_file_path{}; // Establert per setConfigFile()
|
||||
|
||||
// Funcions públiques
|
||||
// Funciones públiques
|
||||
|
||||
void init(); // Inicialitzar amb valors per defecte
|
||||
void init(); // Inicialitzar con valors per defecte
|
||||
void setConfigFile(
|
||||
const std::string& path); // Establir ruta del fitxer de config
|
||||
const std::string& path); // Establir ruta del file de config
|
||||
auto loadFromFile() -> bool; // Carregar config YAML
|
||||
auto saveToFile() -> bool; // Guardar config YAML
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// escena_joc.cpp - Implementació de la lògica del joc
|
||||
// © 1999 Visente i Sergi (versió Pascal)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// game_scene.cpp - Implementació de la lógica del juego
|
||||
// © 1999 Visente i Sergi (versión Pascal)
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "game_scene.hpp"
|
||||
|
||||
@@ -34,39 +34,39 @@ GameScene::GameScene(SDLManager& sdl, SceneContext& context)
|
||||
floating_score_manager_(sdl.getRenderer()),
|
||||
text_(sdl.getRenderer()),
|
||||
init_hud_rect_sound_played_(false) {
|
||||
// Recuperar configuració de match des del context
|
||||
// Recuperar configuración de match des del context
|
||||
match_config_ = context_.getMatchConfig();
|
||||
|
||||
// Debug output de la configuració
|
||||
std::cout << "[GameScene] Configuració de match - P1: "
|
||||
// Debug output de la configuración
|
||||
std::cout << "[GameScene] Configuración de match - P1: "
|
||||
<< (match_config_.jugador1_actiu ? "ACTIU" : "INACTIU")
|
||||
<< ", P2: "
|
||||
<< (match_config_.jugador2_actiu ? "ACTIU" : "INACTIU")
|
||||
<< '\n';
|
||||
|
||||
// Consumir opcions (preparació per MODE_DEMO futur)
|
||||
// Consumir opciones (preparació per MODE_DEMO futur)
|
||||
auto option = context_.consumeOption();
|
||||
(void)option; // Suprimir warning de variable no usada
|
||||
|
||||
// Inicialitzar naus amb renderer (P1=ship.shp, P2=ship2.shp)
|
||||
// Inicialitzar naves con renderer (P1=ship.shp, P2=ship2.shp)
|
||||
ships_[0] = Ship(sdl.getRenderer(), "ship.shp"); // Jugador 1: nave estàndar
|
||||
ships_[1] = Ship(sdl.getRenderer(), "ship2.shp"); // Jugador 2: interceptor amb ales
|
||||
ships_[1] = Ship(sdl.getRenderer(), "ship2.shp"); // Jugador 2: interceptor con ales
|
||||
|
||||
// Inicialitzar bales amb renderer
|
||||
// Inicialitzar balas con renderer
|
||||
for (auto& bullet : bullets_) {
|
||||
bullet = Bullet(sdl.getRenderer());
|
||||
}
|
||||
|
||||
// Inicialitzar enemics amb renderer
|
||||
// Inicialitzar enemigos con renderer
|
||||
for (auto& enemy : enemies_) {
|
||||
enemy = Enemy(sdl.getRenderer());
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::run() {
|
||||
std::cout << "SceneType Joc: Inicialitzant...\n";
|
||||
std::cout << "SceneType Juego: Inicialitzant...\n";
|
||||
|
||||
// Inicialitzar state del joc
|
||||
// Inicialitzar state del juego
|
||||
init();
|
||||
|
||||
SDL_Event event;
|
||||
@@ -78,16 +78,16 @@ void GameScene::run() {
|
||||
float delta_time = (current_time - last_time) / 1000.0F;
|
||||
last_time = current_time;
|
||||
|
||||
// Limitar delta_time per evitar grans salts
|
||||
// Limitar delta_time per evitar grandes salts
|
||||
delta_time = std::min(delta_time, 0.05F);
|
||||
|
||||
// Actualitzar comptador de FPS
|
||||
// Actualitzar counter de FPS
|
||||
sdl_.updateFPS(delta_time);
|
||||
|
||||
// Actualitzar visibilitat del cursor (auto-ocultar)
|
||||
Mouse::updateCursorVisibility();
|
||||
|
||||
// Actualitzar sistema d'input ABANS del event loop
|
||||
// Actualitzar sistema de input ABANS del event loop
|
||||
Input::get()->update();
|
||||
|
||||
// Processar events SDL
|
||||
@@ -101,29 +101,29 @@ void GameScene::run() {
|
||||
GlobalEvents::handle(event, sdl_, context_);
|
||||
}
|
||||
|
||||
// Actualitzar física del joc amb delta_time real
|
||||
// Actualitzar física del juego con delta_time real
|
||||
update(delta_time);
|
||||
|
||||
// Actualitzar sistema d'audio
|
||||
// Actualitzar sistema de audio
|
||||
Audio::update();
|
||||
|
||||
// Actualitzar colors oscil·lats
|
||||
sdl_.updateColors(delta_time);
|
||||
|
||||
// Netejar pantalla (usa color oscil·lat)
|
||||
sdl_.neteja(0, 0, 0);
|
||||
sdl_.clear(0, 0, 0);
|
||||
|
||||
// Actualitzar context de renderitzat (factor d'scale global)
|
||||
// Actualitzar context de renderizado (factor de scale global)
|
||||
sdl_.updateRenderingContext();
|
||||
|
||||
// Dibuixar joc
|
||||
// Dibuixar juego
|
||||
draw();
|
||||
|
||||
// Presentar renderer (swap buffers)
|
||||
sdl_.presenta();
|
||||
sdl_.present();
|
||||
}
|
||||
|
||||
std::cout << "SceneType Joc: Finalitzant...\n";
|
||||
std::cout << "SceneType Juego: Finalitzant...\n";
|
||||
}
|
||||
|
||||
void GameScene::init() {
|
||||
@@ -145,7 +145,7 @@ void GameScene::init() {
|
||||
stage_manager_->init();
|
||||
|
||||
// [NEW] Set ship position reference for safe spawn (P1 for now, TODO: dual tracking)
|
||||
stage_manager_->get_spawn_controller().set_ship_position(&ships_[0].getCenter());
|
||||
stage_manager_->getSpawnController().set_ship_position(&ships_[0].getCenter());
|
||||
|
||||
// Inicialitzar timers de muerte per player
|
||||
hit_timer_per_player_[0] = 0.0F;
|
||||
@@ -165,12 +165,12 @@ void GameScene::init() {
|
||||
score_per_player_[1] = 0;
|
||||
floating_score_manager_.reset();
|
||||
|
||||
// DEPRECATED: spawn_position_ ja no s'usa, es calcula dinàmicament amb obtenir_punt_spawn(player_id)
|
||||
// DEPRECATED: spawn_position_ ya no s'usa, es calcula dinàmicament con obtenir_punt_spawn(player_id)
|
||||
// const SDL_FRect& zona = Defaults::Zones::PLAYAREA;
|
||||
// spawn_position_.x = zona.x + zona.w * 0.5f;
|
||||
// spawn_position_.y = zona.y + zona.h * Defaults::Game::INIT_HUD_SHIP_START_Y_RATIO;
|
||||
|
||||
// Inicialitzar naus segons configuració (només jugadors active)
|
||||
// Inicialitzar naves segons configuración (solo jugadors active)
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
bool jugador_actiu = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu;
|
||||
|
||||
@@ -180,10 +180,10 @@ void GameScene::init() {
|
||||
ships_[i].init(&spawn_pos, false); // No invulnerability at start
|
||||
std::cout << "[GameScene] Jugador " << (i + 1) << " inicialitzat\n";
|
||||
} else {
|
||||
// Jugador inactiu: marcar com a mort permanent
|
||||
// Jugador inactiu: marcar como a mort permanent
|
||||
ships_[i].markHit();
|
||||
hit_timer_per_player_[i] = 999.0F; // Valor sentinella (permanent inactiu)
|
||||
lives_per_player_[i] = 0; // Sense vides
|
||||
lives_per_player_[i] = 0; // Sin vides
|
||||
std::cout << "[GameScene] Jugador " << (i + 1) << " inactiu\n";
|
||||
}
|
||||
}
|
||||
@@ -195,16 +195,16 @@ void GameScene::init() {
|
||||
// DON'T call enemy.init() here - stage system handles spawning
|
||||
}
|
||||
|
||||
// Inicialitzar bales (now 6 instead of 3)
|
||||
// Inicialitzar balas (now 6 instead of 3)
|
||||
for (auto& bullet : bullets_) {
|
||||
bullet.init();
|
||||
}
|
||||
|
||||
// [ELIMINAT] Iniciar música de joc (ara es gestiona en stage_manager)
|
||||
// La música s'inicia quan es transiciona de INIT_HUD a LEVEL_START
|
||||
// [ELIMINAT] Iniciar música de juego (ara es gestiona en stage_manager)
|
||||
// La música s'inicia cuando es transiciona de INIT_HUD a LEVEL_START
|
||||
// Audio::get()->playMusic("game.ogg");
|
||||
|
||||
// Reset flag de sons d'animació
|
||||
// Reset flag de sons de animación
|
||||
init_hud_rect_sound_played_ = false;
|
||||
}
|
||||
|
||||
@@ -213,14 +213,14 @@ void GameScene::update(float delta_time) {
|
||||
if (game_over_state_ == GameOverState::NONE) {
|
||||
auto* input = Input::get();
|
||||
|
||||
// Jugador 1 dispara (només si està active)
|
||||
// Jugador 1 dispara (solo si está active)
|
||||
if (match_config_.jugador1_actiu) {
|
||||
if (input->checkActionPlayer1(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||
disparar_bala(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Jugador 2 dispara (només si està active)
|
||||
// Jugador 2 dispara (solo si está active)
|
||||
if (match_config_.jugador2_actiu) {
|
||||
if (input->checkActionPlayer2(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||
disparar_bala(1);
|
||||
@@ -287,9 +287,9 @@ void GameScene::update(float delta_time) {
|
||||
game_over_timer_ -= delta_time;
|
||||
|
||||
if (game_over_timer_ <= 0.0F) {
|
||||
// Aturar música de joc abans de tornar al títol
|
||||
// Aturar música de juego antes de tornar al título
|
||||
Audio::get()->stopMusic();
|
||||
// Transició a pantalla de títol
|
||||
// Transición a pantalla de título
|
||||
context_.setNextScene(SceneType::TITLE);
|
||||
SceneManager::actual = SceneType::TITLE;
|
||||
return;
|
||||
@@ -374,8 +374,8 @@ void GameScene::update(float delta_time) {
|
||||
// Update stage manager timer (pot canviar l'state!)
|
||||
stage_manager_->update(delta_time);
|
||||
|
||||
// [FIX] Si l'state ha canviat durant update(), sortir immediatament
|
||||
// per evitar recalcular la posició de la ship amb el nou timer
|
||||
// [FIX] Si l'state ha canviat durante update(), salir immediatament
|
||||
// per evitar recalcular la posición de la ship con el nuevo timer
|
||||
if (stage_manager_->get_estat() != StageSystem::EstatStage::INIT_HUD) {
|
||||
break;
|
||||
}
|
||||
@@ -395,7 +395,7 @@ void GameScene::update(float delta_time) {
|
||||
Defaults::Game::INIT_HUD_SHIP2_RATIO_INIT,
|
||||
Defaults::Game::INIT_HUD_SHIP2_RATIO_END);
|
||||
|
||||
// [MODIFICAT] Animar AMBAS naus con sus progress respectivos
|
||||
// [MODIFICAT] Animar AMBAS naves con sus progress respectivos
|
||||
if (match_config_.jugador1_actiu && ship1_progress < 1.0F) {
|
||||
Vec2 pos_p1 = calcular_posicio_nau_init_hud(ship1_progress, 0);
|
||||
ships_[0].setCenter(pos_p1);
|
||||
@@ -406,8 +406,8 @@ void GameScene::update(float delta_time) {
|
||||
ships_[1].setCenter(pos_p2);
|
||||
}
|
||||
|
||||
// Una vegada l'animació acaba, permetre control normal
|
||||
// però mantenir la posició inicial especial fins LEVEL_START
|
||||
// Una vez l'animación acaba, permetre control normal
|
||||
// pero mantenir la posición inicial especial hasta LEVEL_START
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -444,13 +444,13 @@ void GameScene::update(float delta_time) {
|
||||
|
||||
case StageSystem::EstatStage::PLAYING: {
|
||||
// [NEW] Update stage manager (spawns enemies, pause if BOTH dead)
|
||||
bool pausar_spawn = (hit_timer_per_player_[0] > 0.0F && hit_timer_per_player_[1] > 0.0F);
|
||||
stage_manager_->get_spawn_controller().update(delta_time, enemies_, pausar_spawn);
|
||||
bool pause_spawn = (hit_timer_per_player_[0] > 0.0F && hit_timer_per_player_[1] > 0.0F);
|
||||
stage_manager_->getSpawnController().update(delta_time, enemies_, pause_spawn);
|
||||
|
||||
// [NEW] Check stage completion (only when at least one player alive)
|
||||
bool algun_jugador_viu = (hit_timer_per_player_[0] == 0.0F || hit_timer_per_player_[1] == 0.0F);
|
||||
if (algun_jugador_viu) {
|
||||
auto& spawn_ctrl = stage_manager_->get_spawn_controller();
|
||||
auto& spawn_ctrl = stage_manager_->getSpawnController();
|
||||
if (spawn_ctrl.tots_enemics_destruits(enemies_)) {
|
||||
stage_manager_->stage_completat();
|
||||
Audio::get()->playSound(Defaults::Sound::GOOD_JOB_COMMANDER, Audio::Group::GAME);
|
||||
@@ -552,7 +552,7 @@ void GameScene::draw() {
|
||||
constexpr float scale = Defaults::Game::GameOverScreen::TEXT_SCALE;
|
||||
constexpr float spacing = Defaults::Game::GameOverScreen::TEXT_SPACING;
|
||||
|
||||
// Calcular centre de l'àrea de joc usant constants
|
||||
// Calcular centro de l'àrea de juego usant constants
|
||||
const SDL_FRect& play_area = Defaults::Zones::PLAYAREA;
|
||||
float centre_x = play_area.x + (play_area.w / 2.0F);
|
||||
float centre_y = play_area.y + (play_area.h / 2.0F);
|
||||
@@ -568,7 +568,7 @@ void GameScene::draw() {
|
||||
|
||||
switch (state) {
|
||||
case StageSystem::EstatStage::INIT_HUD: {
|
||||
// Calcular progrés de cada animació independent
|
||||
// Calcular progrés de cada animación independent
|
||||
float timer = stage_manager_->get_timer_transicio();
|
||||
float total_time = Defaults::Game::INIT_HUD_DURATION;
|
||||
float global_progress = 1.0F - (timer / total_time);
|
||||
@@ -596,7 +596,7 @@ void GameScene::draw() {
|
||||
|
||||
// Dibuixar elements animats
|
||||
if (rect_progress > 0.0F) {
|
||||
// [NOU] Reproduir so quan comença l'animació del rectangle
|
||||
// [NOU] Reproduir so cuando comença l'animación del rectangle
|
||||
if (!init_hud_rect_sound_played_) {
|
||||
Audio::get()->playSound(Defaults::Sound::INIT_HUD, Audio::Group::GAME);
|
||||
init_hud_rect_sound_played_ = true;
|
||||
@@ -609,7 +609,7 @@ void GameScene::draw() {
|
||||
dibuixar_marcador_animat(score_progress);
|
||||
}
|
||||
|
||||
// [MODIFICAT] Dibuixar naus amb progress independent
|
||||
// [MODIFICAT] Dibuixar naves con progress independent
|
||||
if (ship1_progress > 0.0F && match_config_.jugador1_actiu && !ships_[0].isHit()) {
|
||||
ships_[0].draw();
|
||||
}
|
||||
@@ -735,7 +735,7 @@ void GameScene::tocado(uint8_t player_id) {
|
||||
}
|
||||
|
||||
void GameScene::dibuixar_marges() const {
|
||||
// Dibuixar rectangle de la zona de joc
|
||||
// Dibuixar rectangle de la zona de juego
|
||||
const SDL_FRect& zona = Defaults::Zones::PLAYAREA;
|
||||
|
||||
// Coordenades dels cantons
|
||||
@@ -755,22 +755,22 @@ void GameScene::dibuixar_marcador() {
|
||||
// Construir text del marcador
|
||||
std::string text = buildScoreboard();
|
||||
|
||||
// Paràmetres de renderització
|
||||
// Parámetros de renderització
|
||||
const float scale = 0.85F;
|
||||
const float spacing = 0.0F;
|
||||
|
||||
// Calcular centre de la zona del marcador
|
||||
// Calcular centro de la zona del marcador
|
||||
const SDL_FRect& scoreboard = Defaults::Zones::SCOREBOARD;
|
||||
float centre_x = scoreboard.w / 2.0F;
|
||||
float centre_y = scoreboard.y + (scoreboard.h / 2.0F);
|
||||
|
||||
// Renderitzar centrat
|
||||
// Renderizar centrat
|
||||
text_.renderCentered(text, {.x = centre_x, .y = centre_y}, scale, spacing);
|
||||
}
|
||||
|
||||
void GameScene::dibuixar_marges_animat(float progress) const {
|
||||
// Animació seqüencial del rectangle amb efecte de "pinzell"
|
||||
// Dos pinzells comencen al centre superior i baixen pels laterals
|
||||
// Animación seqüencial del rectangle con efecte de "pinzell"
|
||||
// Dos pinzells comencen al centro superior i baixen por los laterals
|
||||
|
||||
const SDL_FRect& zona = Defaults::Zones::PLAYAREA;
|
||||
|
||||
@@ -792,11 +792,11 @@ void GameScene::dibuixar_marges_animat(float progress) const {
|
||||
if (eased_progress > 0.0F) {
|
||||
float phase1_progress = std::min(eased_progress / PHASE_1_END, 1.0F);
|
||||
|
||||
// Línia esquerra: creix des del centre cap a l'esquerra
|
||||
// Línia izquierda: creix des del centro hacia l'izquierda
|
||||
int x1_phase1 = static_cast<int>(cx - ((cx - x1) * phase1_progress));
|
||||
Rendering::linea(sdl_.getRenderer(), cx, y1, x1_phase1, y1);
|
||||
|
||||
// Línia dreta: creix des del centre cap a la dreta
|
||||
// Línia derecha: creix des del centro hacia la derecha
|
||||
int x2_phase1 = static_cast<int>(cx + ((x2 - cx) * phase1_progress));
|
||||
Rendering::linea(sdl_.getRenderer(), cx, y1, x2_phase1, y1);
|
||||
}
|
||||
@@ -805,11 +805,11 @@ void GameScene::dibuixar_marges_animat(float progress) const {
|
||||
if (eased_progress > PHASE_1_END) {
|
||||
float phase2_progress = std::min((eased_progress - PHASE_1_END) / (PHASE_2_END - PHASE_1_END), 1.0F);
|
||||
|
||||
// Línia esquerra: creix des de dalt cap a baix
|
||||
// Línia izquierda: creix desde dalt hacia baix
|
||||
int y2_phase2 = static_cast<int>(y1 + ((y2 - y1) * phase2_progress));
|
||||
Rendering::linea(sdl_.getRenderer(), x1, y1, x1, y2_phase2);
|
||||
|
||||
// Línia dreta: creix des de dalt cap a baix
|
||||
// Línia derecha: creix desde dalt hacia baix
|
||||
Rendering::linea(sdl_.getRenderer(), x2, y1, x2, y2_phase2);
|
||||
}
|
||||
|
||||
@@ -817,46 +817,46 @@ void GameScene::dibuixar_marges_animat(float progress) const {
|
||||
if (eased_progress > PHASE_2_END) {
|
||||
float phase3_progress = (eased_progress - PHASE_2_END) / (1.0F - PHASE_2_END);
|
||||
|
||||
// Línia esquerra: creix des de l'esquerra cap al centre
|
||||
// Línia izquierda: creix desde l'izquierda hacia el centro
|
||||
int x_left_phase3 = static_cast<int>(x1 + ((cx - x1) * phase3_progress));
|
||||
Rendering::linea(sdl_.getRenderer(), x1, y2, x_left_phase3, y2);
|
||||
|
||||
// Línia dreta: creix des de la dreta cap al centre
|
||||
// Línia derecha: creix desde la derecha hacia el centro
|
||||
int x_right_phase3 = static_cast<int>(x2 - ((x2 - cx) * phase3_progress));
|
||||
Rendering::linea(sdl_.getRenderer(), x2, y2, x_right_phase3, y2);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::dibuixar_marcador_animat(float progress) {
|
||||
// Animació del marcador pujant des de baix amb easing
|
||||
// Animación del marcador pujant desde baix con easing
|
||||
|
||||
// Calcular progrés amb easing
|
||||
// Calcular progrés con easing
|
||||
float eased_progress = Easing::ease_out_quad(progress);
|
||||
|
||||
// Construir text
|
||||
std::string text = buildScoreboard();
|
||||
|
||||
// Paràmetres
|
||||
// Parámetros
|
||||
const float scale = 0.85F;
|
||||
const float spacing = 0.0F;
|
||||
|
||||
// Calcular centre de la zona del marcador
|
||||
// Calcular centro de la zona del marcador
|
||||
const SDL_FRect& scoreboard = Defaults::Zones::SCOREBOARD;
|
||||
float centre_x = scoreboard.w / 2.0F;
|
||||
float centre_y_final = scoreboard.y + (scoreboard.h / 2.0F);
|
||||
|
||||
// Posició Y inicial (offscreen, sota de la pantalla)
|
||||
// Posición Y inicial (offscreen, sota de la pantalla)
|
||||
auto centre_y_inicial = static_cast<float>(Defaults::Game::HEIGHT);
|
||||
|
||||
// Interpolació amb easing
|
||||
// Interpolació con easing
|
||||
float centre_y_animada = centre_y_inicial + ((centre_y_final - centre_y_inicial) * eased_progress);
|
||||
|
||||
// Renderitzar centrat en posició animada
|
||||
// Renderizar centrat en posición animada
|
||||
text_.renderCentered(text, {.x = centre_x, .y = centre_y_animada}, scale, spacing);
|
||||
}
|
||||
|
||||
Vec2 GameScene::calcular_posicio_nau_init_hud(float progress, uint8_t player_id) const {
|
||||
// Animació de la ship pujant des de baix amb easing
|
||||
// Animación de la ship pujant desde baix con easing
|
||||
// [MODIFICAT] Ambas naves usan ease_out_quad (desfase temporal via INIT/END)
|
||||
|
||||
// Aplicar easing (uniforme para ambas naves)
|
||||
@@ -864,16 +864,16 @@ Vec2 GameScene::calcular_posicio_nau_init_hud(float progress, uint8_t player_id)
|
||||
|
||||
const SDL_FRect& zona = Defaults::Zones::PLAYAREA;
|
||||
|
||||
// Calcular posició final segons player (reutilitza obtenir_punt_spawn)
|
||||
// Calcular posición final segons player (reutilitza obtenir_punt_spawn)
|
||||
Vec2 spawn_final = obtenir_punt_spawn(player_id);
|
||||
float x_final = spawn_final.x;
|
||||
float y_final = spawn_final.y;
|
||||
|
||||
// Y inicial: offscreen, 50px sota la zona de joc
|
||||
// Y inicial: offscreen, 50px sota la zona de juego
|
||||
float y_inicial = zona.y + zona.h + 50.0F;
|
||||
|
||||
// X no canvia (destí segons player_id)
|
||||
// Y interpola amb easing
|
||||
// Y interpola con easing
|
||||
float y_animada = y_inicial + ((y_final - y_inicial) * eased_progress);
|
||||
|
||||
return {.x = x_final, .y = y_animada};
|
||||
@@ -905,7 +905,7 @@ float GameScene::calcular_progress_rango(float global_progress, float ratio_init
|
||||
}
|
||||
|
||||
std::string GameScene::buildScoreboard() const {
|
||||
// Puntuació P1 (6 dígits) - mostrar zeros si inactiu
|
||||
// Puntuación P1 (6 dígits) - mostrar zeros si inactiu
|
||||
std::string score_p1;
|
||||
std::string vides_p1;
|
||||
if (match_config_.jugador1_actiu) {
|
||||
@@ -919,12 +919,12 @@ std::string GameScene::buildScoreboard() const {
|
||||
vides_p1 = "00";
|
||||
}
|
||||
|
||||
// Nivell (2 dígits)
|
||||
// Nivel (2 dígits)
|
||||
uint8_t stage_num = stage_manager_->get_stage_actual();
|
||||
std::string stage_str = (stage_num < 10) ? "0" + std::to_string(stage_num)
|
||||
: std::to_string(stage_num);
|
||||
|
||||
// Puntuació P2 (6 dígits) - mostrar zeros si inactiu
|
||||
// Puntuación P2 (6 dígits) - mostrar zeros si inactiu
|
||||
std::string score_p2;
|
||||
std::string vides_p2;
|
||||
if (match_config_.jugador2_actiu) {
|
||||
@@ -939,7 +939,7 @@ std::string GameScene::buildScoreboard() const {
|
||||
}
|
||||
|
||||
// Format: "123456 03 LEVEL 01 654321 02"
|
||||
// Nota: dos espais entre seccions, mantenir ambdós slots sempre visibles
|
||||
// Nota: dos espais entre seccions, mantenir ambdós slots siempre visibles
|
||||
return score_p1 + " " + vides_p1 + " LEVEL " + stage_str + " " + score_p2 + " " + vides_p2;
|
||||
}
|
||||
|
||||
@@ -947,13 +947,13 @@ void GameScene::detectar_col·lisions_bales_enemics() {
|
||||
// Amplificador per hitbox més generós (115%)
|
||||
constexpr float AMPLIFIER = Defaults::Game::COLLISION_BULLET_ENEMY_AMPLIFIER;
|
||||
|
||||
// Velocitat d'explosió reduïda per efecte suau
|
||||
// Velocidad de explosión reduïda per efecte suau
|
||||
constexpr float VELOCITAT_EXPLOSIO = 80.0F; // px/s (en lloc de 80.0f per defecte)
|
||||
|
||||
// Iterar per totes les bales i enemics
|
||||
// Iterar per todas las balas i enemigos
|
||||
for (auto& bullet : bullets_) {
|
||||
for (auto& enemy : enemies_) {
|
||||
// Comprovar col·lisió utilitzant la interfície genèrica
|
||||
// Comprovar colisión utilitzant la interfície genèrica
|
||||
if (Physics::check_collision(bullet, enemy, AMPLIFIER)) {
|
||||
// *** COL·LISIÓ DETECTADA ***
|
||||
|
||||
@@ -980,17 +980,17 @@ void GameScene::detectar_col·lisions_bales_enemics() {
|
||||
// 3. Create floating score number
|
||||
floating_score_manager_.crear(points, pos_enemic);
|
||||
|
||||
// 4. Destruir enemy (marca com inactiu)
|
||||
// 4. Destruir enemy (marca como inactiu)
|
||||
enemy.destruir();
|
||||
|
||||
// 2. Crear explosió de fragments
|
||||
// 2. Crear explosión de fragments
|
||||
Vec2 vel_enemic = enemy.getVelocityVector();
|
||||
debris_manager_.explode(
|
||||
enemy.getShape(), // Forma vectorial del pentàgon
|
||||
pos_enemic, // Posició central
|
||||
0.0F, // Angle (enemy té rotació interna)
|
||||
enemy.getShape(), // Forma vectorial del pentágono
|
||||
pos_enemic, // Posición central
|
||||
0.0F, // Angle (enemy té rotación interna)
|
||||
1.0F, // Escala normal
|
||||
VELOCITAT_EXPLOSIO, // 50 px/s (explosió suau)
|
||||
VELOCITAT_EXPLOSIO, // 50 px/s (explosión suau)
|
||||
enemy.getBrightness(), // Heredar brightness
|
||||
vel_enemic, // Heredar velocity
|
||||
enemy.get_drotacio(), // Heredar velocity angular (trayectorias curvas)
|
||||
@@ -1000,7 +1000,7 @@ void GameScene::detectar_col·lisions_bales_enemics() {
|
||||
// 3. Desactivar bullet
|
||||
bullet.desactivar();
|
||||
|
||||
// 4. Eixir del bucle intern (bullet només destrueix 1 enemy)
|
||||
// 4. Eixir del bucle intern (bullet solo destrueix 1 enemy)
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1031,7 +1031,7 @@ void GameScene::detectar_col·lisio_naus_enemics() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Comprovar col·lisió utilitzant la interfície genèrica
|
||||
// Comprovar colisión utilitzant la interfície genèrica
|
||||
if (Physics::check_collision(ships_[i], enemy, AMPLIFIER)) {
|
||||
tocado(i); // Trigger death sequence for player i
|
||||
break; // Only one collision per player per frame
|
||||
@@ -1082,7 +1082,7 @@ void GameScene::detectar_col·lisions_bales_jugadors() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Comprovar col·lisió utilitzant la interfície genèrica
|
||||
// Comprovar colisión utilitzant la interfície genèrica
|
||||
if (Physics::check_collision(bullet, ships_[player_id], AMPLIFIER)) {
|
||||
// *** FRIENDLY FIRE HIT ***
|
||||
|
||||
@@ -1095,7 +1095,7 @@ void GameScene::detectar_col·lisions_bales_jugadors() {
|
||||
// Victim loses 1 life
|
||||
tocado(player_id);
|
||||
|
||||
// Attacker gains 1 life (no cap)
|
||||
// Attacker gains 1 life (no sin)
|
||||
lives_per_player_[bullet_owner]++;
|
||||
}
|
||||
|
||||
@@ -1187,7 +1187,7 @@ Vec2 GameScene::obtenir_punt_spawn(uint8_t player_id) const {
|
||||
|
||||
float x_ratio;
|
||||
if (match_config_.es_un_jugador()) {
|
||||
// Un sol player: spawn al centre (50%)
|
||||
// Un sol player: spawn al centro (50%)
|
||||
x_ratio = 0.5F;
|
||||
} else {
|
||||
// Dos jugadors: spawn a posicions separades
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// escena_joc.hpp - Lògica principal del joc
|
||||
// © 1999 Visente i Sergi (versió Pascal)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// game_scene.hpp - Lógica principal del juego
|
||||
// © 1999 Visente i Sergi (versión Pascal)
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#ifndef ESCENA_JOC_HPP
|
||||
#define ESCENA_JOC_HPP
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
@@ -31,7 +30,7 @@ enum class GameOverState {
|
||||
GAME_OVER // Final game over (returning to title)
|
||||
};
|
||||
|
||||
// Classe principal del joc (escena)
|
||||
// Clase principal del juego (escena)
|
||||
class GameScene {
|
||||
public:
|
||||
explicit GameScene(SDLManager& sdl, SceneManager::SceneContext& context);
|
||||
@@ -45,13 +44,13 @@ class GameScene {
|
||||
private:
|
||||
SDLManager& sdl_;
|
||||
SceneManager::SceneContext& context_;
|
||||
GameConfig::MatchConfig match_config_; // Configuració de jugadors active
|
||||
GameConfig::MatchConfig match_config_; // Configuración de jugadors active
|
||||
|
||||
// Efectes visuals
|
||||
Effects::DebrisManager debris_manager_;
|
||||
Effects::FloatingScoreManager floating_score_manager_;
|
||||
|
||||
// Estat del joc
|
||||
// Estat del juego
|
||||
std::array<Ship, 2> ships_; // [0]=P1, [1]=P2
|
||||
std::array<Enemy, Constants::MAX_ORNIS> enemies_;
|
||||
std::array<Bullet, Constants::MAX_BALES * 2> bullets_; // 6 balas: P1=[0,1,2], P2=[3,4,5]
|
||||
@@ -74,16 +73,16 @@ class GameScene {
|
||||
std::unique_ptr<StageSystem::StageSystemConfig> stage_config_;
|
||||
std::unique_ptr<StageSystem::StageManager> stage_manager_;
|
||||
|
||||
// Control de sons d'animació INIT_HUD
|
||||
// Control de sons de animación INIT_HUD
|
||||
bool init_hud_rect_sound_played_; // Flag para evitar repetir sonido del rectángulo
|
||||
|
||||
// Funcions privades
|
||||
// Funciones privades
|
||||
void tocado(uint8_t player_id);
|
||||
void detectar_col·lisions_bales_enemics(); // Col·lisions bullet-enemy
|
||||
void detectar_col·lisions_bales_enemics(); // Colisiones bullet-enemy
|
||||
void detectar_col·lisio_naus_enemics(); // Ship-enemy collision detection (plural)
|
||||
void detectar_col·lisions_bales_jugadors(); // Bullet-player collision detection (friendly fire)
|
||||
void dibuixar_marges() const; // Dibuixar vores de la zona de joc
|
||||
void dibuixar_marcador(); // Dibuixar marcador de puntuació
|
||||
void dibuixar_marges() const; // Dibuixar vores de la zona de juego
|
||||
void dibuixar_marcador(); // Dibuixar marcador de puntuación
|
||||
void disparar_bala(uint8_t player_id); // Shoot bullet from player
|
||||
[[nodiscard]] Vec2 obtenir_punt_spawn(uint8_t player_id) const; // Get spawn position for player
|
||||
|
||||
@@ -97,16 +96,14 @@ class GameScene {
|
||||
// [NEW] Stage system helpers
|
||||
void dibuixar_missatge_stage(const std::string& message);
|
||||
|
||||
// [NEW] Funcions d'animació per INIT_HUD
|
||||
void dibuixar_marges_animat(float progress) const; // Rectangle amb creixement uniforme
|
||||
void dibuixar_marcador_animat(float progress); // Marcador que puja des de baix
|
||||
[[nodiscard]] Vec2 calcular_posicio_nau_init_hud(float progress, uint8_t player_id) const; // Posició animada de la ship
|
||||
// [NEW] Funciones de animación per INIT_HUD
|
||||
void dibuixar_marges_animat(float progress) const; // Rectangle con creixement uniforme
|
||||
void dibuixar_marcador_animat(float progress); // Marcador que puja desde baix
|
||||
[[nodiscard]] Vec2 calcular_posicio_nau_init_hud(float progress, uint8_t player_id) const; // Posición animada de la ship
|
||||
|
||||
// [NEW] Función helper del sistema de animación INIT_HUD
|
||||
[[nodiscard]] float calcular_progress_rango(float global_progress, float ratio_init, float ratio_end) const;
|
||||
|
||||
// [NEW] Funció helper del marcador
|
||||
// [NEW] Función helper del marcador
|
||||
[[nodiscard]] std::string buildScoreboard() const;
|
||||
};
|
||||
|
||||
#endif // ESCENA_JOC_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// escena_logo.cpp - Implementació de l'escena logo
|
||||
// logo_scene.cpp - Implementació de l'escena logo
|
||||
// © 2025 Port a C++20
|
||||
|
||||
#include "logo_scene.hpp"
|
||||
@@ -22,8 +22,8 @@ using SceneManager::SceneContext;
|
||||
using SceneType = SceneContext::SceneType;
|
||||
using Option = SceneContext::Option;
|
||||
|
||||
// Helper: calcular el progrés individual d'una lletra
|
||||
// en funció del progrés global (efecte seqüencial)
|
||||
// Helper: calcular el progrés individual de una lletra
|
||||
// en función del progrés global (efecte seqüencial)
|
||||
static float calcular_progress_letra(size_t letra_index, size_t num_letras, float global_progress, float threshold) {
|
||||
if (num_letras == 0) {
|
||||
return 1.0F;
|
||||
@@ -37,7 +37,7 @@ static float calcular_progress_letra(size_t letra_index, size_t num_letras, floa
|
||||
|
||||
// Interpolar progrés
|
||||
if (global_progress < start) {
|
||||
return 0.0F; // Encara no ha començat
|
||||
return 0.0F; // Aún no ha començat
|
||||
}
|
||||
if (global_progress >= end) {
|
||||
return 1.0F; // Completament apareguda
|
||||
@@ -55,7 +55,7 @@ LogoScene::LogoScene(SDLManager& sdl, SceneContext& context)
|
||||
temps_des_ultima_explosio_(0.0F) {
|
||||
std::cout << "SceneType Logo: Inicialitzant...\n";
|
||||
|
||||
// Consumir opcions (LOGO no processa opcions actualment)
|
||||
// Consumir opciones (LOGO no processa opciones actualment)
|
||||
auto option = context_.consumeOption();
|
||||
(void)option; // Suprimir warning
|
||||
|
||||
@@ -64,9 +64,9 @@ LogoScene::LogoScene(SDLManager& sdl, SceneContext& context)
|
||||
}
|
||||
|
||||
LogoScene::~LogoScene() {
|
||||
// Aturar tots els sons i la música
|
||||
// Aturar todos los sons y la música
|
||||
Audio::get()->stopAllSounds();
|
||||
std::cout << "SceneType Logo: Sons aturats\n";
|
||||
std::cout << "SceneType Logo: Sons parados\n";
|
||||
}
|
||||
|
||||
void LogoScene::run() {
|
||||
@@ -79,16 +79,16 @@ void LogoScene::run() {
|
||||
float delta_time = (current_time - last_time) / 1000.0F;
|
||||
last_time = current_time;
|
||||
|
||||
// Limitar delta_time per evitar grans salts
|
||||
// Limitar delta_time per evitar grandes salts
|
||||
delta_time = std::min(delta_time, 0.05F);
|
||||
|
||||
// Actualitzar comptador de FPS
|
||||
// Actualitzar counter de FPS
|
||||
sdl_.updateFPS(delta_time);
|
||||
|
||||
// Actualitzar visibilitat del cursor (auto-ocultar)
|
||||
Mouse::updateCursorVisibility();
|
||||
|
||||
// Actualitzar sistema d'input ABANS del event loop
|
||||
// Actualitzar sistema de input ABANS del event loop
|
||||
Input::get()->update();
|
||||
|
||||
// Processar events SDL
|
||||
@@ -103,17 +103,17 @@ void LogoScene::run() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Processar events de l'escena (qualsevol tecla/clic salta al joc)
|
||||
// Processar events de l'escena (qualsevol tecla/clic salta al juego)
|
||||
processar_events(event);
|
||||
}
|
||||
|
||||
// Actualitzar lògica
|
||||
// Actualitzar lógica
|
||||
update(delta_time);
|
||||
|
||||
// Actualitzar colors oscil·lats (efecte verd global)
|
||||
sdl_.updateColors(delta_time);
|
||||
|
||||
// Actualitzar context de renderitzat (factor d'scale global)
|
||||
// Actualitzar context de renderizado (factor de scale global)
|
||||
sdl_.updateRenderingContext();
|
||||
|
||||
// Dibuixar
|
||||
@@ -126,8 +126,8 @@ void LogoScene::run() {
|
||||
void LogoScene::inicialitzar_lletres() {
|
||||
using namespace Graphics;
|
||||
|
||||
// Llista de fitxers .shp (A repetida per a les dues A's)
|
||||
std::vector<std::string> fitxers = {
|
||||
// Llista de archivos .shp (A repetida para las dues A's)
|
||||
std::vector<std::string> archivos = {
|
||||
"logo/letra_j.shp",
|
||||
"logo/letra_a.shp",
|
||||
"logo/letra_i.shp",
|
||||
@@ -138,13 +138,13 @@ void LogoScene::inicialitzar_lletres() {
|
||||
"logo/letra_e.shp",
|
||||
"logo/letra_s.shp"};
|
||||
|
||||
// Pas 1: Carregar totes les formes i calcular amplades
|
||||
// Pas 1: Carregar todas las formes i calcular amplades
|
||||
float ancho_total = 0.0F;
|
||||
|
||||
for (const auto& fitxer : fitxers) {
|
||||
auto shape = ShapeLoader::load(fitxer);
|
||||
for (const auto& file : archivos) {
|
||||
auto shape = ShapeLoader::load(file);
|
||||
if (!shape || !shape->isValid()) {
|
||||
std::cerr << "[LogoScene] Error carregant " << fitxer << '\n';
|
||||
std::cerr << "[LogoScene] Error carregant " << file << '\n';
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -161,23 +161,23 @@ void LogoScene::inicialitzar_lletres() {
|
||||
|
||||
float ancho_sin_escalar = max_x - min_x;
|
||||
|
||||
// IMPORTANT: Escalar ancho i offset amb ESCALA_FINAL
|
||||
// per que les posicions finals coincideixin amb la mida real de les lletres
|
||||
// IMPORTANT: Escalar ancho i offset con ESCALA_FINAL
|
||||
// per que las posicions finals coincideixin con la mida real de las lletres
|
||||
float ancho = ancho_sin_escalar * ESCALA_FINAL;
|
||||
float offset_centre = (shape->getCenter().x - min_x) * ESCALA_FINAL;
|
||||
|
||||
lletres_.push_back({shape,
|
||||
{.x = 0.0F, .y = 0.0F}, // Posició es calcularà després
|
||||
{.x = 0.0F, .y = 0.0F}, // Posición es calcularà después
|
||||
ancho,
|
||||
offset_centre});
|
||||
|
||||
ancho_total += ancho;
|
||||
}
|
||||
|
||||
// Pas 2: Afegir espaiat entre lletres
|
||||
// Pas 2: Añadir espaiat entre lletres
|
||||
ancho_total += ESPAI_ENTRE_LLETRES * (lletres_.size() - 1);
|
||||
|
||||
// Pas 3: Calcular posició inicial (centrat horitzontal)
|
||||
// Pas 3: Calcular posición inicial (centrat horitzontal)
|
||||
constexpr float PANTALLA_ANCHO = 640.0F;
|
||||
constexpr float PANTALLA_ALTO = 480.0F;
|
||||
|
||||
@@ -188,13 +188,13 @@ void LogoScene::inicialitzar_lletres() {
|
||||
float x_actual = x_inicial;
|
||||
|
||||
for (auto& lletra : lletres_) {
|
||||
// Posicionar el centre de la shape (shape_centre) en pantalla
|
||||
// Posicionar el centro de la shape (shape_centre) en pantalla
|
||||
// Usar offset_centre en lloc de ancho/2 perquè shape_centre
|
||||
// pot no estar exactament al mig del bounding box
|
||||
lletra.position.x = x_actual + lletra.offset_centre;
|
||||
lletra.position.y = y_centre;
|
||||
|
||||
// Avançar per a següent lletra
|
||||
// Avançar para següent lletra
|
||||
x_actual += lletra.ancho + ESPAI_ENTRE_LLETRES;
|
||||
}
|
||||
|
||||
@@ -206,12 +206,12 @@ void LogoScene::canviar_estat(AnimationState nou_estat) {
|
||||
estat_actual_ = nou_estat;
|
||||
temps_estat_actual_ = 0.0F; // Reset time
|
||||
|
||||
// Inicialitzar state d'explosió
|
||||
// Inicialitzar state de explosión
|
||||
if (nou_estat == AnimationState::EXPLOSION) {
|
||||
lletra_explosio_index_ = 0;
|
||||
temps_des_ultima_explosio_ = 0.0F;
|
||||
|
||||
// Generar ordre aleatori d'explosions
|
||||
// Generar ordre aleatori de explosions
|
||||
ordre_explosio_.clear();
|
||||
for (size_t i = 0; i < lletres_.size(); i++) {
|
||||
ordre_explosio_.push_back(i);
|
||||
@@ -228,14 +228,14 @@ void LogoScene::canviar_estat(AnimationState nou_estat) {
|
||||
}
|
||||
|
||||
bool LogoScene::totes_lletres_completes() const {
|
||||
// Quan global_progress = 1.0, totes les lletres tenen letra_progress = 1.0
|
||||
// Cuando global_progress = 1.0, todas las lletres tenen letra_progress = 1.0
|
||||
return temps_estat_actual_ >= DURACIO_ZOOM;
|
||||
}
|
||||
|
||||
void LogoScene::actualitzar_explosions(float delta_time) {
|
||||
temps_des_ultima_explosio_ += delta_time;
|
||||
|
||||
// Comprovar si és el moment d'explode la següent lletra
|
||||
// Comprovar si es el moment de explode la següent lletra
|
||||
if (temps_des_ultima_explosio_ >= DELAY_ENTRE_EXPLOSIONS) {
|
||||
if (lletra_explosio_index_ < lletres_.size()) {
|
||||
// Explotar lletra actual (en ordre aleatori)
|
||||
@@ -244,12 +244,12 @@ void LogoScene::actualitzar_explosions(float delta_time) {
|
||||
|
||||
debris_manager_->explode(
|
||||
lletra.shape, // Forma a explode
|
||||
lletra.position, // Posició
|
||||
0.0F, // Angle (sense rotació)
|
||||
lletra.position, // Posición
|
||||
0.0F, // Angle (sin rotación)
|
||||
ESCALA_FINAL, // Escala (lletres a scale final)
|
||||
VELOCITAT_EXPLOSIO, // Velocitat base
|
||||
VELOCITAT_EXPLOSIO, // Velocidad base
|
||||
1.0F, // Brightness màxim (per defecte)
|
||||
{.x = 0.0F, .y = 0.0F} // Sense velocity (per defecte)
|
||||
{.x = 0.0F, .y = 0.0F} // Sin velocity (per defecte)
|
||||
);
|
||||
|
||||
std::cout << "[LogoScene] Explota lletra " << lletra_explosio_index_ << "\n";
|
||||
@@ -258,7 +258,7 @@ void LogoScene::actualitzar_explosions(float delta_time) {
|
||||
lletra_explosio_index_++;
|
||||
temps_des_ultima_explosio_ = 0.0F;
|
||||
} else {
|
||||
// Totes les lletres han explotat, transició a POST_EXPLOSION
|
||||
// Todas las lletres han explotat, transición a POST_EXPLOSION
|
||||
canviar_estat(AnimationState::POST_EXPLOSION);
|
||||
}
|
||||
}
|
||||
@@ -275,7 +275,7 @@ void LogoScene::update(float delta_time) {
|
||||
break;
|
||||
|
||||
case AnimationState::ANIMATION: {
|
||||
// Reproduir so per cada lletra quan comença a aparèixer
|
||||
// Reproduir so per cada lletra cuando comença a aparèixer
|
||||
float global_progress = std::min(temps_estat_actual_ / DURACIO_ZOOM, 1.0F);
|
||||
|
||||
for (size_t i = 0; i < lletres_.size() && i < so_reproduit_.size(); i++) {
|
||||
@@ -286,7 +286,7 @@ void LogoScene::update(float delta_time) {
|
||||
global_progress,
|
||||
THRESHOLD_LETRA);
|
||||
|
||||
// Reproduir so quan la lletra comença a aparèixer (progress > 0)
|
||||
// Reproduir so cuando la lletra comença a aparèixer (progress > 0)
|
||||
if (letra_progress > 0.0F) {
|
||||
Audio::get()->playSound(Defaults::Sound::LOGO, Audio::Group::GAME);
|
||||
so_reproduit_[i] = true;
|
||||
@@ -312,7 +312,7 @@ void LogoScene::update(float delta_time) {
|
||||
|
||||
case AnimationState::POST_EXPLOSION:
|
||||
if (temps_estat_actual_ >= DURACIO_POST_EXPLOSION) {
|
||||
// Transició a pantalla de títol
|
||||
// Transición a pantalla de título
|
||||
context_.setNextScene(SceneType::TITLE);
|
||||
SceneManager::actual = SceneType::TITLE;
|
||||
}
|
||||
@@ -325,21 +325,21 @@ void LogoScene::update(float delta_time) {
|
||||
SceneManager::actual = SceneType::TITLE;
|
||||
}
|
||||
|
||||
// Actualitzar animacions de debris
|
||||
// Actualitzar animaciones de debris
|
||||
debris_manager_->update(delta_time);
|
||||
}
|
||||
|
||||
void LogoScene::draw() {
|
||||
// Fons negre
|
||||
sdl_.neteja(0, 0, 0);
|
||||
sdl_.clear(0, 0, 0);
|
||||
|
||||
// PRE_ANIMATION: Només pantalla negra
|
||||
// PRE_ANIMATION: Solo pantalla negra
|
||||
if (estat_actual_ == AnimationState::PRE_ANIMATION) {
|
||||
sdl_.presenta();
|
||||
return; // No renderitzar lletres
|
||||
sdl_.present();
|
||||
return; // No renderizar lletres
|
||||
}
|
||||
|
||||
// ANIMATION o POST_ANIMATION: Dibuixar lletres amb animació
|
||||
// ANIMATION o POST_ANIMATION: Dibuixar lletres con animación
|
||||
if (estat_actual_ == AnimationState::ANIMATION ||
|
||||
estat_actual_ == AnimationState::POST_ANIMATION) {
|
||||
float global_progress =
|
||||
@@ -383,15 +383,15 @@ void LogoScene::draw() {
|
||||
}
|
||||
}
|
||||
|
||||
// EXPLOSION: Dibuixar només lletres que encara no han explotat
|
||||
// EXPLOSION: Dibuixar solo lletres que aún no han explotat
|
||||
if (estat_actual_ == AnimationState::EXPLOSION) {
|
||||
// Crear conjunt de lletres ja explotades
|
||||
// Crear conjunt de lletres ya explotades
|
||||
std::set<size_t> explotades;
|
||||
for (size_t i = 0; i < lletra_explosio_index_; i++) {
|
||||
explotades.insert(ordre_explosio_[i]);
|
||||
}
|
||||
|
||||
// Dibuixar només lletres que NO han explotat
|
||||
// Dibuixar solo lletres que NO han explotat
|
||||
for (size_t i = 0; i < lletres_.size(); i++) {
|
||||
if (!explotades.contains(i)) {
|
||||
const auto& lletra = lletres_[i];
|
||||
@@ -407,12 +407,12 @@ void LogoScene::draw() {
|
||||
}
|
||||
}
|
||||
|
||||
// POST_EXPLOSION: No draw lletres, només debris (a baix)
|
||||
// POST_EXPLOSION: No draw lletres, solo debris (a baix)
|
||||
|
||||
// Sempre draw debris (si n'hi ha d'active)
|
||||
// Siempre draw debris (si n'hay de active)
|
||||
debris_manager_->draw();
|
||||
|
||||
sdl_.presenta();
|
||||
sdl_.present();
|
||||
}
|
||||
|
||||
auto LogoScene::checkSkipButtonPressed() -> bool {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// escena_logo.hpp - Pantalla d'inici del joc
|
||||
// Mostra logo JAILGAMES animat amb zoom i salta al joc
|
||||
// logo_scene.hpp - Pantalla de start del juego
|
||||
// Muestra logo JAILGAMES animat con zoom i salta al juego
|
||||
// © 2025 Port a C++20
|
||||
|
||||
#pragma once
|
||||
@@ -25,59 +25,59 @@ class LogoScene {
|
||||
void run(); // Bucle principal de l'escena
|
||||
|
||||
private:
|
||||
// Màquina d'estats per l'animació
|
||||
// Màquina de estats per l'animación
|
||||
enum class AnimationState {
|
||||
PRE_ANIMATION, // Pantalla negra inicial
|
||||
ANIMATION, // Animació de zoom de lletres
|
||||
ANIMATION, // Animación de zoom de lletres
|
||||
POST_ANIMATION, // Logo complet visible
|
||||
EXPLOSION, // Explosió seqüencial de lletres
|
||||
POST_EXPLOSION // Espera després de l'última explosió
|
||||
EXPLOSION, // Explosión seqüencial de lletres
|
||||
POST_EXPLOSION // Espera después de l'última explosión
|
||||
};
|
||||
|
||||
SDLManager& sdl_;
|
||||
SceneManager::SceneContext& context_;
|
||||
AnimationState estat_actual_; // Estat actual de la màquina
|
||||
float
|
||||
temps_estat_actual_; // Temps en l'state actual (reset en cada transició)
|
||||
temps_estat_actual_; // Temps en l'state actual (reset en cada transición)
|
||||
|
||||
// Gestor de fragments d'explosions
|
||||
// Gestor de fragments de explosions
|
||||
std::unique_ptr<Effects::DebrisManager> debris_manager_;
|
||||
|
||||
// Seguiment d'explosions seqüencials
|
||||
// Seguiment de explosions seqüencials
|
||||
size_t lletra_explosio_index_; // Índex de la següent lletra a explode
|
||||
float temps_des_ultima_explosio_; // Temps des de l'última explosió
|
||||
std::vector<size_t> ordre_explosio_; // Ordre aleatori d'índexs de lletres
|
||||
float temps_des_ultima_explosio_; // Temps desde l'última explosión
|
||||
std::vector<size_t> ordre_explosio_; // Ordre aleatori de índexs de lletres
|
||||
|
||||
// Estructura per a cada lletra del logo
|
||||
// Estructura para cada lletra del logo
|
||||
struct LetraLogo {
|
||||
std::shared_ptr<Graphics::Shape> shape;
|
||||
Vec2 position; // Posició final en pantalla
|
||||
Vec2 position; // Posición final en pantalla
|
||||
float ancho; // Ancho del bounding box
|
||||
float offset_centre; // Distància de min_x a shape_centre.x
|
||||
float offset_centre; // Distancia de min_x a shape_centre.x
|
||||
};
|
||||
|
||||
std::vector<LetraLogo> lletres_; // 9 lletres: J-A-I-L-G-A-M-E-S
|
||||
|
||||
// Seguiment de sons de lletres (evitar reproduccions repetides)
|
||||
std::array<bool, 9> so_reproduit_; // Track si cada lletra ja ha reproduit el so
|
||||
std::array<bool, 9> so_reproduit_; // Track si cada lletra ya ha reproduit el so
|
||||
|
||||
// Constants d'animació
|
||||
// Constants de animación
|
||||
static constexpr float DURACIO_PRE = 1.5F; // Duració PRE_ANIMATION (pantalla negra)
|
||||
static constexpr float DURACIO_ZOOM = 4.0F; // Duració del zoom (segons)
|
||||
static constexpr float DURACIO_POST_ANIMATION = 3.0F; // Duració POST_ANIMATION (logo complet)
|
||||
static constexpr float DURACIO_POST_EXPLOSION = 3.0F; // Duració POST_EXPLOSION (espera final)
|
||||
static constexpr float DELAY_ENTRE_EXPLOSIONS = 0.1F; // Temps entre explosions de lletres
|
||||
static constexpr float VELOCITAT_EXPLOSIO = 240.0F; // Velocitat base fragments (px/s)
|
||||
static constexpr float VELOCITAT_EXPLOSIO = 240.0F; // Velocidad base fragments (px/s)
|
||||
static constexpr float ESCALA_INICIAL = 0.1F; // Escala inicial (10%)
|
||||
static constexpr float ESCALA_FINAL = 0.8F; // Escala final (80%)
|
||||
static constexpr float ESPAI_ENTRE_LLETRES = 10.0F; // Espaiat entre lletres
|
||||
|
||||
// Constants d'animació seqüencial
|
||||
// Constants de animación seqüencial
|
||||
static constexpr float THRESHOLD_LETRA = 0.6F; // Umbral per activar següent lletra (0.0-1.0)
|
||||
static constexpr float ORIGEN_ZOOM_X = Defaults::Game::WIDTH * 0.5F; // Vec2 inicial X del zoom
|
||||
static constexpr float ORIGEN_ZOOM_Y = Defaults::Game::HEIGHT * 0.4F; // Vec2 inicial Y del zoom
|
||||
|
||||
// Mètodes privats
|
||||
// Métodos privats
|
||||
void inicialitzar_lletres();
|
||||
void update(float delta_time);
|
||||
void actualitzar_explosions(float delta_time);
|
||||
@@ -85,7 +85,7 @@ class LogoScene {
|
||||
void processar_events(const SDL_Event& event);
|
||||
auto checkSkipButtonPressed() -> bool;
|
||||
|
||||
// Mètodes de gestió d'estats
|
||||
// Métodos de gestió de estats
|
||||
void canviar_estat(AnimationState nou_estat);
|
||||
[[nodiscard]] bool totes_lletres_completes() const;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// escena_titol.cpp - Implementació de l'escena de títol
|
||||
// title_scene.cpp - Implementació de l'escena de título
|
||||
// © 2025 Port a C++20
|
||||
|
||||
#include "title_scene.hpp"
|
||||
@@ -36,16 +36,16 @@ TitleScene::TitleScene(SDLManager& sdl, SceneContext& context)
|
||||
factor_lerp_(0.0F) {
|
||||
std::cout << "SceneType Titol: Inicialitzant...\n";
|
||||
|
||||
// Inicialitzar configuració de match (cap player active per defecte)
|
||||
// Inicialitzar configuración de match (sin player active per defecte)
|
||||
match_config_.jugador1_actiu = false;
|
||||
match_config_.jugador2_actiu = false;
|
||||
match_config_.mode = GameConfig::Mode::NORMAL;
|
||||
|
||||
// Processar opció del context
|
||||
// Processar opción del context
|
||||
auto option = context_.consumeOption();
|
||||
|
||||
if (option == Option::JUMP_TO_TITLE_MAIN) {
|
||||
std::cout << "SceneType Titol: Opció JUMP_TO_TITLE_MAIN activada\n";
|
||||
std::cout << "SceneType Titol: Opción JUMP_TO_TITLE_MAIN activada\n";
|
||||
estat_actual_ = TitleState::MAIN;
|
||||
temps_estat_main_ = 0.0F;
|
||||
}
|
||||
@@ -68,16 +68,16 @@ TitleScene::TitleScene(SDLManager& sdl, SceneContext& context)
|
||||
150 // densitat: 150 estrelles (50 per capa)
|
||||
);
|
||||
|
||||
// Brightness depèn de l'opció
|
||||
// Brightness depèn de l'opción
|
||||
if (estat_actual_ == TitleState::MAIN) {
|
||||
// Si saltem a MAIN, starfield instantàniament brillant
|
||||
starfield_->set_brightness(BRIGHTNESS_STARFIELD);
|
||||
} else {
|
||||
// Flux normal: comença amb brightness 0.0 per fade-in
|
||||
// Flux normal: comença con brightness 0.0 per fade-in
|
||||
starfield_->set_brightness(0.0F);
|
||||
}
|
||||
|
||||
// Inicialitzar animador de naus 3D
|
||||
// Inicialitzar animador de naves 3D
|
||||
ship_animator_ = std::make_unique<Title::ShipAnimator>(sdl_.getRenderer());
|
||||
ship_animator_->init();
|
||||
|
||||
@@ -90,17 +90,17 @@ TitleScene::TitleScene(SDLManager& sdl, SceneContext& context)
|
||||
ship_animator_->set_visible(false);
|
||||
}
|
||||
|
||||
// Inicialitzar lletres del títol "ORNI ATTACK!"
|
||||
// Inicialitzar lletres del título "ORNI ATTACK!"
|
||||
inicialitzar_titol();
|
||||
|
||||
// Iniciar música de títol si no està sonant
|
||||
// Iniciar música de título si no está sonant
|
||||
if (Audio::get()->getMusicState() != Audio::MusicState::PLAYING) {
|
||||
Audio::get()->playMusic("title.ogg");
|
||||
}
|
||||
}
|
||||
|
||||
TitleScene::~TitleScene() {
|
||||
// Aturar música de títol quan es destrueix l'escena
|
||||
// Aturar música de título cuando es destrueix l'escena
|
||||
Audio::get()->stopMusic();
|
||||
}
|
||||
|
||||
@@ -117,10 +117,10 @@ void TitleScene::inicialitzar_titol() {
|
||||
// Pas 1: Carregar formes i calcular amplades per "ORNI"
|
||||
float ancho_total_orni = 0.0F;
|
||||
|
||||
for (const auto& fitxer : fitxers_orni) {
|
||||
auto shape = ShapeLoader::load(fitxer);
|
||||
for (const auto& file : fitxers_orni) {
|
||||
auto shape = ShapeLoader::load(file);
|
||||
if (!shape || !shape->isValid()) {
|
||||
std::cerr << "[TitleScene] Error carregant " << fitxer << '\n';
|
||||
std::cerr << "[TitleScene] Error carregant " << file << '\n';
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ void TitleScene::inicialitzar_titol() {
|
||||
float ancho_sin_escalar = max_x - min_x;
|
||||
float altura_sin_escalar = max_y - min_y;
|
||||
|
||||
// Escalar ancho, altura i offset amb LOGO_SCALE
|
||||
// Escalar ancho, altura i offset con LOGO_SCALE
|
||||
float ancho = ancho_sin_escalar * Defaults::Title::Layout::LOGO_SCALE;
|
||||
float altura = altura_sin_escalar * Defaults::Title::Layout::LOGO_SCALE;
|
||||
float offset_centre = (shape->getCenter().x - min_x) * Defaults::Title::Layout::LOGO_SCALE;
|
||||
@@ -152,10 +152,10 @@ void TitleScene::inicialitzar_titol() {
|
||||
ancho_total_orni += ancho;
|
||||
}
|
||||
|
||||
// Afegir espaiat entre lletres
|
||||
// Añadir espaiat entre lletres
|
||||
ancho_total_orni += ESPAI_ENTRE_LLETRES * (lletres_orni_.size() - 1);
|
||||
|
||||
// Calcular posició inicial (centrat horitzontal) per "ORNI"
|
||||
// Calcular posición inicial (centrat horitzontal) per "ORNI"
|
||||
float x_inicial_orni = (Defaults::Game::WIDTH - ancho_total_orni) / 2.0F;
|
||||
float x_actual = x_inicial_orni;
|
||||
|
||||
@@ -168,8 +168,8 @@ void TitleScene::inicialitzar_titol() {
|
||||
std::cout << "[TitleScene] Línia 1 (ORNI): " << lletres_orni_.size()
|
||||
<< " lletres, ancho total: " << ancho_total_orni << " px\n";
|
||||
|
||||
// === Calcular posició Y dinàmica per "ATTACK!" ===
|
||||
// Totes les lletres ORNI tenen la mateixa altura, utilitzem la primera
|
||||
// === Calcular posición Y dinàmica per "ATTACK!" ===
|
||||
// Todas las lletres ORNI tenen la misma altura, utilitzem la primera
|
||||
float altura_orni = lletres_orni_.empty() ? 50.0F : lletres_orni_[0].altura;
|
||||
float y_orni = Defaults::Game::HEIGHT * Defaults::Title::Layout::LOGO_POS;
|
||||
float separacion_lineas = Defaults::Game::HEIGHT * Defaults::Title::Layout::LOGO_LINE_SPACING;
|
||||
@@ -191,10 +191,10 @@ void TitleScene::inicialitzar_titol() {
|
||||
// Pas 1: Carregar formes i calcular amplades per "ATTACK!"
|
||||
float ancho_total_attack = 0.0F;
|
||||
|
||||
for (const auto& fitxer : fitxers_attack) {
|
||||
auto shape = ShapeLoader::load(fitxer);
|
||||
for (const auto& file : fitxers_attack) {
|
||||
auto shape = ShapeLoader::load(file);
|
||||
if (!shape || !shape->isValid()) {
|
||||
std::cerr << "[TitleScene] Error carregant " << fitxer << '\n';
|
||||
std::cerr << "[TitleScene] Error carregant " << file << '\n';
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ void TitleScene::inicialitzar_titol() {
|
||||
float ancho_sin_escalar = max_x - min_x;
|
||||
float altura_sin_escalar = max_y - min_y;
|
||||
|
||||
// Escalar ancho, altura i offset amb LOGO_SCALE
|
||||
// Escalar ancho, altura i offset con LOGO_SCALE
|
||||
float ancho = ancho_sin_escalar * Defaults::Title::Layout::LOGO_SCALE;
|
||||
float altura = altura_sin_escalar * Defaults::Title::Layout::LOGO_SCALE;
|
||||
float offset_centre = (shape->getCenter().x - min_x) * Defaults::Title::Layout::LOGO_SCALE;
|
||||
@@ -226,23 +226,23 @@ void TitleScene::inicialitzar_titol() {
|
||||
ancho_total_attack += ancho;
|
||||
}
|
||||
|
||||
// Afegir espaiat entre lletres
|
||||
// Añadir espaiat entre lletres
|
||||
ancho_total_attack += ESPAI_ENTRE_LLETRES * (lletres_attack_.size() - 1);
|
||||
|
||||
// Calcular posició inicial (centrat horitzontal) per "ATTACK!"
|
||||
// Calcular posición inicial (centrat horitzontal) per "ATTACK!"
|
||||
float x_inicial_attack = (Defaults::Game::WIDTH - ancho_total_attack) / 2.0F;
|
||||
x_actual = x_inicial_attack;
|
||||
|
||||
for (auto& lletra : lletres_attack_) {
|
||||
lletra.position.x = x_actual + lletra.offset_centre;
|
||||
lletra.position.y = y_attack_dinamica_; // Usar posició dinàmica
|
||||
lletra.position.y = y_attack_dinamica_; // Usar posición dinàmica
|
||||
x_actual += lletra.ancho + ESPAI_ENTRE_LLETRES;
|
||||
}
|
||||
|
||||
std::cout << "[TitleScene] Línia 2 (ATTACK!): " << lletres_attack_.size()
|
||||
<< " lletres, ancho total: " << ancho_total_attack << " px\n";
|
||||
|
||||
// Guardar posicions originals per l'animació orbital
|
||||
// Guardar posicions originals per l'animación orbital
|
||||
posicions_originals_orni_.clear();
|
||||
for (const auto& lletra : lletres_orni_) {
|
||||
posicions_originals_orni_.push_back(lletra.position);
|
||||
@@ -253,7 +253,7 @@ void TitleScene::inicialitzar_titol() {
|
||||
posicions_originals_attack_.push_back(lletra.position);
|
||||
}
|
||||
|
||||
std::cout << "[TitleScene] Animació: Posicions originals guardades\n";
|
||||
std::cout << "[TitleScene] Animación: Posicions originals guardades\n";
|
||||
}
|
||||
|
||||
void TitleScene::run() {
|
||||
@@ -266,16 +266,16 @@ void TitleScene::run() {
|
||||
float delta_time = (current_time - last_time) / 1000.0F;
|
||||
last_time = current_time;
|
||||
|
||||
// Limitar delta_time per evitar grans salts
|
||||
// Limitar delta_time per evitar grandes salts
|
||||
delta_time = std::min(delta_time, 0.05F);
|
||||
|
||||
// Actualitzar comptador de FPS
|
||||
// Actualitzar counter de FPS
|
||||
sdl_.updateFPS(delta_time);
|
||||
|
||||
// Actualitzar visibilitat del cursor (auto-ocultar)
|
||||
Mouse::updateCursorVisibility();
|
||||
|
||||
// Actualitzar sistema d'input ABANS del event loop
|
||||
// Actualitzar sistema de input ABANS del event loop
|
||||
Input::get()->update();
|
||||
|
||||
// Processar events SDL
|
||||
@@ -294,38 +294,38 @@ void TitleScene::run() {
|
||||
processar_events(event);
|
||||
}
|
||||
|
||||
// Actualitzar lògica
|
||||
// Actualitzar lógica
|
||||
update(delta_time);
|
||||
|
||||
// Actualitzar sistema d'audio
|
||||
// Actualitzar sistema de audio
|
||||
Audio::update();
|
||||
|
||||
// Actualitzar colors oscil·lats
|
||||
sdl_.updateColors(delta_time);
|
||||
|
||||
// Netejar pantalla
|
||||
sdl_.neteja(0, 0, 0);
|
||||
sdl_.clear(0, 0, 0);
|
||||
|
||||
// Actualitzar context de renderitzat (factor d'scale global)
|
||||
// Actualitzar context de renderizado (factor de scale global)
|
||||
sdl_.updateRenderingContext();
|
||||
|
||||
// Dibuixar
|
||||
draw();
|
||||
|
||||
// Presentar renderer (swap buffers)
|
||||
sdl_.presenta();
|
||||
sdl_.present();
|
||||
}
|
||||
|
||||
std::cout << "SceneType Titol: Finalitzant...\n";
|
||||
}
|
||||
|
||||
void TitleScene::update(float delta_time) {
|
||||
// Actualitzar starfield (sempre active)
|
||||
// Actualitzar starfield (siempre active)
|
||||
if (starfield_) {
|
||||
starfield_->update(delta_time);
|
||||
}
|
||||
|
||||
// Actualitzar naus (quan visibles)
|
||||
// Actualitzar naves (cuando visibles)
|
||||
if (ship_animator_ &&
|
||||
(estat_actual_ == TitleState::STARFIELD_FADE_IN ||
|
||||
estat_actual_ == TitleState::STARFIELD ||
|
||||
@@ -345,11 +345,11 @@ void TitleScene::update(float delta_time) {
|
||||
float brightness_actual = progress * BRIGHTNESS_STARFIELD;
|
||||
starfield_->set_brightness(brightness_actual);
|
||||
|
||||
// Transició a STARFIELD quan el fade es completa
|
||||
// Transición a STARFIELD cuando el fade es completa
|
||||
if (temps_acumulat_ >= DURACIO_FADE_IN) {
|
||||
estat_actual_ = TitleState::STARFIELD;
|
||||
temps_acumulat_ = 0.0F; // Reset timer per al següent state
|
||||
starfield_->set_brightness(BRIGHTNESS_STARFIELD); // Assegurar valor final
|
||||
starfield_->set_brightness(BRIGHTNESS_STARFIELD); // Assegurar value final
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -360,16 +360,16 @@ void TitleScene::update(float delta_time) {
|
||||
estat_actual_ = TitleState::MAIN;
|
||||
temps_estat_main_ = 0.0F; // Reset timer al entrar a MAIN
|
||||
animacio_activa_ = false; // Comença estàtic
|
||||
factor_lerp_ = 0.0F; // Sense animació encara
|
||||
factor_lerp_ = 0.0F; // Sin animación aún
|
||||
|
||||
// Naus esperaran ENTRANCE_DELAY abans d'entrar (no iniciar aquí)
|
||||
// Naves esperaran ENTRANCE_DELAY antes de entrar (no start aquí)
|
||||
}
|
||||
break;
|
||||
|
||||
case TitleState::MAIN: {
|
||||
temps_estat_main_ += delta_time;
|
||||
|
||||
// Iniciar animació d'entrada de naus després del delay
|
||||
// Iniciar animación de entrada de naves después del delay
|
||||
if (temps_estat_main_ >= Defaults::Title::Ships::ENTRANCE_DELAY) {
|
||||
if (ship_animator_ && !ship_animator_->is_visible()) {
|
||||
ship_animator_->set_visible(true);
|
||||
@@ -388,13 +388,13 @@ void TitleScene::update(float delta_time) {
|
||||
factor_lerp_ = temps_lerp / DURACIO_LERP; // 0.0 → 1.0 linealment
|
||||
animacio_activa_ = true;
|
||||
}
|
||||
// Fase 3: Animació completa (12s+)
|
||||
// Fase 3: Animación completa (12s+)
|
||||
else {
|
||||
factor_lerp_ = 1.0F;
|
||||
animacio_activa_ = true;
|
||||
}
|
||||
|
||||
// Actualitzar animació del logo
|
||||
// Actualitzar animación del logo
|
||||
actualitzar_animacio_logo(delta_time);
|
||||
break;
|
||||
}
|
||||
@@ -402,10 +402,10 @@ void TitleScene::update(float delta_time) {
|
||||
case TitleState::PLAYER_JOIN_PHASE:
|
||||
temps_acumulat_ += delta_time;
|
||||
|
||||
// Continuar animació orbital durant la transició
|
||||
// Continuar animación orbital durante la transición
|
||||
actualitzar_animacio_logo(delta_time);
|
||||
|
||||
// [NOU] Continuar comprovant si l'altre player vol unir-se durant la transició ("late join")
|
||||
// [NOU] Continuar comprovant si l'altre player quiere unir-se durante la transición ("late join")
|
||||
{
|
||||
bool p1_actiu_abans = match_config_.jugador1_actiu;
|
||||
bool p2_actiu_abans = match_config_.jugador2_actiu;
|
||||
@@ -414,7 +414,7 @@ void TitleScene::update(float delta_time) {
|
||||
// Updates match_config_ if pressed, logs are in the method
|
||||
context_.setMatchConfig(match_config_);
|
||||
|
||||
// Trigger animació de sortida per la ship que acaba d'unir-se
|
||||
// Trigger animación de salida per la ship que acaba de unir-se
|
||||
if (ship_animator_) {
|
||||
if (match_config_.jugador1_actiu && !p1_actiu_abans) {
|
||||
ship_animator_->trigger_exit_animation_for_player(1);
|
||||
@@ -426,10 +426,10 @@ void TitleScene::update(float delta_time) {
|
||||
}
|
||||
}
|
||||
|
||||
// Reproducir so de START quan el segon player s'uneix
|
||||
// Reproducir so de START cuando el segon player s'uneix
|
||||
Audio::get()->playSound(Defaults::Sound::START, Audio::Group::GAME);
|
||||
|
||||
// Reiniciar el timer per allargar el time de transició
|
||||
// Reiniciar el timer per allargar el time de transición
|
||||
temps_acumulat_ = 0.0F;
|
||||
|
||||
std::cout << "[TitleScene] Segon player s'ha unit - so i timer reiniciats\n";
|
||||
@@ -437,7 +437,7 @@ void TitleScene::update(float delta_time) {
|
||||
}
|
||||
|
||||
if (temps_acumulat_ >= DURACIO_TRANSITION) {
|
||||
// Transició a pantalla negra
|
||||
// Transición a pantalla negra
|
||||
estat_actual_ = TitleState::BLACK_SCREEN;
|
||||
temps_acumulat_ = 0.0F;
|
||||
std::cout << "[TitleScene] Passant a BLACK_SCREEN\n";
|
||||
@@ -449,7 +449,7 @@ void TitleScene::update(float delta_time) {
|
||||
|
||||
// No animation, no input checking - just wait
|
||||
if (temps_acumulat_ >= DURACIO_BLACK_SCREEN) {
|
||||
// Transició a escena GAME
|
||||
// Transición a escena GAME
|
||||
SceneManager::actual = SceneType::GAME;
|
||||
std::cout << "[TitleScene] Canviant a escena GAME\n";
|
||||
}
|
||||
@@ -464,26 +464,26 @@ void TitleScene::update(float delta_time) {
|
||||
starfield_->set_brightness(BRIGHTNESS_STARFIELD);
|
||||
temps_estat_main_ = 0.0F;
|
||||
|
||||
// Naus esperaran ENTRANCE_DELAY abans d'entrar (no iniciar aquí)
|
||||
// Naves esperaran ENTRANCE_DELAY antes de entrar (no start aquí)
|
||||
}
|
||||
}
|
||||
|
||||
// Verificar boton START para iniciar match desde MAIN
|
||||
// Verificar boton START para start match desde MAIN
|
||||
if (estat_actual_ == TitleState::MAIN) {
|
||||
// Guardar state anterior per detectar qui ha premut START AQUEST frame
|
||||
bool p1_actiu_abans = match_config_.jugador1_actiu;
|
||||
bool p2_actiu_abans = match_config_.jugador2_actiu;
|
||||
|
||||
if (checkStartGameButtonPressed()) {
|
||||
// Si START es prem durant el delay (naus encara invisibles), saltar-les a FLOATING
|
||||
// Si START es prem durante el delay (naves aún invisibles), saltar-las a FLOATING
|
||||
if (ship_animator_ && !ship_animator_->is_visible()) {
|
||||
ship_animator_->set_visible(true);
|
||||
ship_animator_->skip_to_floating_state();
|
||||
}
|
||||
|
||||
// Configurar match abans de canviar d'escena
|
||||
// Configurar match antes de canviar de escena
|
||||
context_.setMatchConfig(match_config_);
|
||||
std::cout << "[TitleScene] Configuració de match - P1: "
|
||||
std::cout << "[TitleScene] Configuración de match - P1: "
|
||||
<< (match_config_.jugador1_actiu ? "ACTIU" : "INACTIU")
|
||||
<< ", P2: "
|
||||
<< (match_config_.jugador2_actiu ? "ACTIU" : "INACTIU")
|
||||
@@ -493,7 +493,7 @@ void TitleScene::update(float delta_time) {
|
||||
estat_actual_ = TitleState::PLAYER_JOIN_PHASE;
|
||||
temps_acumulat_ = 0.0F;
|
||||
|
||||
// Trigger animació de sortida NOMÉS per les naus que han premut START
|
||||
// Trigger animación de salida NOMÉS per las naves que han premut START
|
||||
if (ship_animator_) {
|
||||
if (match_config_.jugador1_actiu && !p1_actiu_abans) {
|
||||
ship_animator_->trigger_exit_animation_for_player(1);
|
||||
@@ -512,7 +512,7 @@ void TitleScene::update(float delta_time) {
|
||||
}
|
||||
|
||||
void TitleScene::actualitzar_animacio_logo(float delta_time) {
|
||||
// Només calcular i aplicar offsets si l'animació està activa
|
||||
// Solo calcular i aplicar offsets si l'animación está activa
|
||||
if (animacio_activa_) {
|
||||
// Acumular time escalat
|
||||
temps_animacio_ += delta_time * factor_lerp_;
|
||||
@@ -527,13 +527,13 @@ void TitleScene::actualitzar_animacio_logo(float delta_time) {
|
||||
float offset_x = amplitude_x_actual * std::sin(2.0F * Defaults::Math::PI * frequency_x_actual * temps_animacio_);
|
||||
float offset_y = amplitude_y_actual * std::sin((2.0F * Defaults::Math::PI * frequency_y_actual * temps_animacio_) + ORBIT_PHASE_OFFSET);
|
||||
|
||||
// Aplicar offset a totes les lletres de "ORNI"
|
||||
// Aplicar offset a todas las lletres de "ORNI"
|
||||
for (size_t i = 0; i < lletres_orni_.size(); ++i) {
|
||||
lletres_orni_[i].position.x = posicions_originals_orni_[i].x + static_cast<int>(std::round(offset_x));
|
||||
lletres_orni_[i].position.y = posicions_originals_orni_[i].y + static_cast<int>(std::round(offset_y));
|
||||
}
|
||||
|
||||
// Aplicar offset a totes les lletres de "ATTACK!"
|
||||
// Aplicar offset a todas las lletres de "ATTACK!"
|
||||
for (size_t i = 0; i < lletres_attack_.size(); ++i) {
|
||||
lletres_attack_[i].position.x = posicions_originals_attack_[i].x + static_cast<int>(std::round(offset_x));
|
||||
lletres_attack_[i].position.y = posicions_originals_attack_[i].y + static_cast<int>(std::round(offset_y));
|
||||
@@ -542,12 +542,12 @@ void TitleScene::actualitzar_animacio_logo(float delta_time) {
|
||||
}
|
||||
|
||||
void TitleScene::draw() {
|
||||
// Dibuixar starfield de fons (en tots els estats excepte BLACK_SCREEN)
|
||||
// Dibuixar starfield de fons (en todos los estats excepte BLACK_SCREEN)
|
||||
if (starfield_ && estat_actual_ != TitleState::BLACK_SCREEN) {
|
||||
starfield_->draw();
|
||||
}
|
||||
|
||||
// Dibuixar naus (després starfield, abans logo)
|
||||
// Dibuixar naves (después starfield, antes logo)
|
||||
if (ship_animator_ &&
|
||||
(estat_actual_ == TitleState::STARFIELD_FADE_IN ||
|
||||
estat_actual_ == TitleState::STARFIELD ||
|
||||
@@ -556,15 +556,15 @@ void TitleScene::draw() {
|
||||
ship_animator_->draw();
|
||||
}
|
||||
|
||||
// En els estats STARFIELD_FADE_IN i STARFIELD, només mostrar starfield (sense text)
|
||||
// En los estats STARFIELD_FADE_IN i STARFIELD, solo mostrar starfield (sin text)
|
||||
if (estat_actual_ == TitleState::STARFIELD_FADE_IN || estat_actual_ == TitleState::STARFIELD) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Estat MAIN i PLAYER_JOIN_PHASE: Dibuixar títol i text (sobre el starfield)
|
||||
// BLACK_SCREEN: no draw res (fons negre ja està netejat)
|
||||
// Estat MAIN i PLAYER_JOIN_PHASE: Dibuixar título i text (sobre el starfield)
|
||||
// BLACK_SCREEN: no draw res (fons negre ya está netejat)
|
||||
if (estat_actual_ == TitleState::MAIN || estat_actual_ == TitleState::PLAYER_JOIN_PHASE) {
|
||||
// === Calcular i renderitzar ombra (només si animació activa) ===
|
||||
// === Calcular i renderizar ombra (solo si animación activa) ===
|
||||
if (animacio_activa_) {
|
||||
float temps_shadow = temps_animacio_ - SHADOW_DELAY;
|
||||
temps_shadow = std::max(temps_shadow, 0.0F); // Evitar time negatiu
|
||||
@@ -642,14 +642,14 @@ void TitleScene::draw() {
|
||||
}
|
||||
|
||||
// === Text "PRESS START TO PLAY" ===
|
||||
// En state MAIN: sempre visible
|
||||
// En state TRANSITION: parpellejant (blink amb sinusoide)
|
||||
// En state MAIN: siempre visible
|
||||
// En state TRANSITION: parpellejant (blink con sinusoide)
|
||||
|
||||
const float spacing = Defaults::Title::Layout::TEXT_SPACING;
|
||||
|
||||
bool mostrar_text = true;
|
||||
if (estat_actual_ == TitleState::PLAYER_JOIN_PHASE) {
|
||||
// Parpelleig: sin oscil·la entre -1 i 1, volem ON quan > 0
|
||||
// Parpelleig: sin oscil·la entre -1 i 1, volem ON cuando > 0
|
||||
float fase = temps_acumulat_ * BLINK_FREQUENCY * 2.0F * std::numbers::pi_v<float>; // 2π × freq × time
|
||||
mostrar_text = (std::sin(fase) > 0.0F);
|
||||
}
|
||||
@@ -689,7 +689,7 @@ void TitleScene::draw() {
|
||||
float y_line1 = Defaults::Game::HEIGHT * Defaults::Title::Layout::COPYRIGHT1_POS;
|
||||
float y_line2 = y_line1 + copy_height + line_spacing; // Línea 2 debajo de línea 1
|
||||
|
||||
// Renderitzar línees centrades
|
||||
// Renderizar línees centrades
|
||||
float centre_x = Defaults::Game::WIDTH / 2.0F;
|
||||
|
||||
text_.renderCentered(copyright_original, {.x = centre_x, .y = y_line1}, escala_copy, spacing);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// escena_titol.hpp - Pantalla de títol del joc
|
||||
// Mostra message "PRESS BUTTON TO PLAY" i copyright
|
||||
// title_scene.hpp - Pantalla de título del juego
|
||||
// Muestra message "PRESS BUTTON TO PLAY" y copyright
|
||||
// © 2025 Port a C++20
|
||||
|
||||
#pragma once
|
||||
@@ -32,81 +32,81 @@ class TitleScene {
|
||||
void run(); // Bucle principal de l'escena
|
||||
|
||||
private:
|
||||
// Màquina d'estats per la pantalla de títol
|
||||
// Màquina de estats per la pantalla de título
|
||||
enum class TitleState {
|
||||
STARFIELD_FADE_IN, // Fade-in del starfield (3.0s)
|
||||
STARFIELD, // Pantalla amb camp d'estrelles (4.0s)
|
||||
MAIN, // Pantalla de títol amb text (indefinit, fins START)
|
||||
PLAYER_JOIN_PHASE, // Fase d'unió de jugadors: fade-out música + text parpellejant (2.5s)
|
||||
BLACK_SCREEN // Pantalla negra de transició (2.0s)
|
||||
STARFIELD, // Pantalla con camp de estrelles (4.0s)
|
||||
MAIN, // Pantalla de título con text (indefinit, hasta START)
|
||||
PLAYER_JOIN_PHASE, // Fase de unió de jugadors: fade-out música + text parpellejant (2.5s)
|
||||
BLACK_SCREEN // Pantalla negra de transición (2.0s)
|
||||
};
|
||||
|
||||
// Estructura per emmagatzemar informació de cada lletra del títol
|
||||
// Estructura per emmagatzemar informació de cada lletra del título
|
||||
struct LetraLogo {
|
||||
std::shared_ptr<Graphics::Shape> shape; // Forma vectorial de la lletra
|
||||
Vec2 position; // Posició en pantalla
|
||||
float ancho; // Amplada escalada
|
||||
float altura; // Altura escalada
|
||||
float offset_centre; // Offset del centre per posicionament
|
||||
Vec2 position; // Posición en pantalla
|
||||
float ancho; // Amplada scaled
|
||||
float altura; // Altura scaled
|
||||
float offset_centre; // Offset del centro per posicionament
|
||||
};
|
||||
|
||||
SDLManager& sdl_;
|
||||
SceneManager::SceneContext& context_;
|
||||
GameConfig::MatchConfig match_config_; // Configuració de jugadors active
|
||||
GameConfig::MatchConfig match_config_; // Configuración de jugadors active
|
||||
Graphics::VectorText text_; // Sistema de text vectorial
|
||||
std::unique_ptr<Graphics::Starfield> starfield_; // Camp d'estrelles de fons
|
||||
std::unique_ptr<Title::ShipAnimator> ship_animator_; // Naus 3D flotants
|
||||
std::unique_ptr<Graphics::Starfield> starfield_; // Camp de estrelles de fons
|
||||
std::unique_ptr<Title::ShipAnimator> ship_animator_; // Naves 3D flotantes
|
||||
TitleState estat_actual_; // Estat actual de la màquina
|
||||
float temps_acumulat_; // Temps acumulat per l'state INIT
|
||||
|
||||
// Lletres del títol "ORNI ATTACK!"
|
||||
// Lletres del título "ORNI ATTACK!"
|
||||
std::vector<LetraLogo> lletres_orni_; // Lletres de "ORNI" (línia 1)
|
||||
std::vector<LetraLogo> lletres_attack_; // Lletres de "ATTACK!" (línia 2)
|
||||
float y_attack_dinamica_; // Posició Y calculada dinàmicament per "ATTACK!"
|
||||
float y_attack_dinamica_; // Posición Y calculada dinàmicament per "ATTACK!"
|
||||
|
||||
// Estat d'animació del logo
|
||||
float temps_animacio_; // Temps acumulat per animació orbital
|
||||
// Estat de animación del logo
|
||||
float temps_animacio_; // Temps acumulat per animación orbital
|
||||
std::vector<Vec2> posicions_originals_orni_; // Posicions originals de "ORNI"
|
||||
std::vector<Vec2> posicions_originals_attack_; // Posicions originals de "ATTACK!"
|
||||
|
||||
// Estat d'arrencada de l'animació
|
||||
// Estat de arrencada de l'animación
|
||||
float temps_estat_main_; // Temps acumulat en state MAIN
|
||||
bool animacio_activa_; // Flag: true quan animació està activa
|
||||
bool animacio_activa_; // Flag: true cuando animación está activa
|
||||
float factor_lerp_; // Factor de lerp actual (0.0 → 1.0)
|
||||
|
||||
// Constants
|
||||
static constexpr float BRIGHTNESS_STARFIELD = 1.2F; // Brightness del starfield (>1.0 = més brillant)
|
||||
static constexpr float DURACIO_FADE_IN = 3.0F; // Duració del fade-in del starfield (1.5 segons)
|
||||
static constexpr float DURACIO_INIT = 4.0F; // Duració de l'state INIT (2 segons)
|
||||
static constexpr float DURACIO_TRANSITION = 2.5F; // Duració de la transició (1.5 segons)
|
||||
static constexpr float DURACIO_TRANSITION = 2.5F; // Duració de la transición (1.5 segons)
|
||||
static constexpr float ESPAI_ENTRE_LLETRES = 10.0F; // Espai entre lletres
|
||||
static constexpr float BLINK_FREQUENCY = 3.0F; // Freqüència de parpelleig (3 Hz)
|
||||
static constexpr float DURACIO_BLACK_SCREEN = 2.0F; // Duració pantalla negra (2 segons)
|
||||
static constexpr int MUSIC_FADE = 1500; // Duracio del fade de la musica del titol al començar a jugar
|
||||
|
||||
// Constants d'animació del logo
|
||||
// Constants de animación del logo
|
||||
static constexpr float ORBIT_AMPLITUDE_X = 4.0F; // Amplitud oscil·lació horitzontal (píxels)
|
||||
static constexpr float ORBIT_AMPLITUDE_Y = 3.0F; // Amplitud oscil·lació vertical (píxels)
|
||||
static constexpr float ORBIT_FREQUENCY_X = 0.8F; // Velocitat oscil·lació horitzontal (Hz)
|
||||
static constexpr float ORBIT_FREQUENCY_Y = 1.2F; // Velocitat oscil·lació vertical (Hz)
|
||||
static constexpr float ORBIT_FREQUENCY_X = 0.8F; // Velocidad oscil·lació horitzontal (Hz)
|
||||
static constexpr float ORBIT_FREQUENCY_Y = 1.2F; // Velocidad oscil·lació vertical (Hz)
|
||||
static constexpr float ORBIT_PHASE_OFFSET = 1.57F; // Desfasament entre X i Y (90° per circular)
|
||||
|
||||
// Constants d'ombra del logo
|
||||
// Constants de ombra del logo
|
||||
static constexpr float SHADOW_DELAY = 0.5F; // Retard temporal de l'ombra (segons)
|
||||
static constexpr float SHADOW_BRIGHTNESS = 0.4F; // Multiplicador de brightness de l'ombra (0.0-1.0)
|
||||
static constexpr float SHADOW_OFFSET_X = 2.0F; // Offset espacial X fix (píxels)
|
||||
static constexpr float SHADOW_OFFSET_Y = 2.0F; // Offset espacial Y fix (píxels)
|
||||
|
||||
// Temporització de l'arrencada de l'animació
|
||||
static constexpr float DELAY_INICI_ANIMACIO = 10.0F; // 10s estàtic abans d'animar
|
||||
// Temporització de l'arrencada de l'animación
|
||||
static constexpr float DELAY_INICI_ANIMACIO = 10.0F; // 10s estàtic antes de animar
|
||||
static constexpr float DURACIO_LERP = 2.0F; // 2s per arribar a amplitud completa
|
||||
|
||||
// Mètodes privats
|
||||
// Métodos privats
|
||||
void update(float delta_time);
|
||||
void actualitzar_animacio_logo(float delta_time); // Actualitza l'animació orbital del logo
|
||||
void actualitzar_animacio_logo(float delta_time); // Actualitza l'animación orbital del logo
|
||||
void draw();
|
||||
void processar_events(const SDL_Event& event);
|
||||
auto checkSkipButtonPressed() -> bool;
|
||||
auto checkStartGameButtonPressed() -> bool;
|
||||
void inicialitzar_titol(); // Carrega i posiciona les lletres del títol
|
||||
void inicialitzar_titol(); // Carrega i posiciona las lletres del título
|
||||
};
|
||||
|
||||
@@ -21,13 +21,13 @@ SpawnController::SpawnController()
|
||||
index_spawn_actual_(0),
|
||||
ship_position_(nullptr) {}
|
||||
|
||||
void SpawnController::configurar(const StageConfig* config) {
|
||||
void SpawnController::configure(const StageConfig* config) {
|
||||
config_ = config;
|
||||
}
|
||||
|
||||
void SpawnController::iniciar() {
|
||||
void SpawnController::start() {
|
||||
if (config_ == nullptr) {
|
||||
std::cerr << "[SpawnController] Error: config_ és null" << '\n';
|
||||
std::cerr << "[SpawnController] Error: config_ es null" << '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ void SpawnController::generar_spawn_events() {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < config_->total_enemics; i++) {
|
||||
for (uint8_t i = 0; i < config_->total_enemies; i++) {
|
||||
float spawn_time = config_->config_spawn.delay_inicial +
|
||||
(i * config_->config_spawn.interval_spawn);
|
||||
|
||||
@@ -143,7 +143,7 @@ EnemyType SpawnController::seleccionar_tipus_aleatori() const {
|
||||
if (std::cmp_less(rand_val, config_->distribucio.pentagon)) {
|
||||
return EnemyType::PENTAGON;
|
||||
}
|
||||
if (rand_val < config_->distribucio.pentagon + config_->distribucio.quadrat) {
|
||||
if (rand_val < config_->distribucio.pentagon + config_->distribucio.cuadrado) {
|
||||
return EnemyType::QUADRAT;
|
||||
}
|
||||
return EnemyType::MOLINILLO;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// spawn_controller.hpp - Controlador de spawn d'enemics
|
||||
// spawn_controller.hpp - Controlador de spawn de enemigos
|
||||
// © 2025 Orni Attack
|
||||
|
||||
#pragma once
|
||||
@@ -16,8 +16,8 @@ namespace StageSystem {
|
||||
// Informació de spawn planificat
|
||||
struct SpawnEvent {
|
||||
float temps_spawn; // Temps absolut (segons) per spawnejar
|
||||
EnemyType type; // Tipus d'enemy
|
||||
bool spawnejat; // Ja s'ha processat?
|
||||
EnemyType type; // Tipo de enemy
|
||||
bool spawnejat; // Ya s'ha processat?
|
||||
};
|
||||
|
||||
class SpawnController {
|
||||
@@ -25,8 +25,8 @@ class SpawnController {
|
||||
SpawnController();
|
||||
|
||||
// Configuration
|
||||
void configurar(const StageConfig* config); // Set stage config
|
||||
void iniciar(); // Generate spawn schedule
|
||||
void configure(const StageConfig* config); // Set stage config
|
||||
void start(); // Generate spawn schedule
|
||||
void reset(); // Clear all pending spawns
|
||||
|
||||
// Update
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// stage_config.hpp - Estructures de dades per configuració d'stages
|
||||
// stage_config.hpp - Estructures de dades per configuración de stages
|
||||
// © 2025 Orni Attack
|
||||
|
||||
#pragma once
|
||||
@@ -10,24 +10,24 @@
|
||||
|
||||
namespace StageSystem {
|
||||
|
||||
// Tipus de mode de spawn
|
||||
// Tipo de mode de spawn
|
||||
enum class ModeSpawn {
|
||||
PROGRESSIVE, // Spawn progressiu amb intervals
|
||||
IMMEDIATE, // Tots els enemics de cop
|
||||
WAVE // Onades de 3-5 enemics (futura extensió)
|
||||
PROGRESSIVE, // Spawn progressiu con intervals
|
||||
IMMEDIATE, // Todos los enemigos de cop
|
||||
WAVE // Onades de 3-5 enemigos (futura extensió)
|
||||
};
|
||||
|
||||
// Configuració de spawn
|
||||
// Configuración de spawn
|
||||
struct ConfigSpawn {
|
||||
ModeSpawn mode;
|
||||
float delay_inicial; // Segons abans del primer spawn
|
||||
float delay_inicial; // Segons antes del primer spawn
|
||||
float interval_spawn; // Segons entre spawns consecutius
|
||||
};
|
||||
|
||||
// Distribució de type d'enemics (percentatges)
|
||||
// Distribució de type de enemigos (percentatges)
|
||||
struct DistribucioEnemics {
|
||||
uint8_t pentagon; // 0-100
|
||||
uint8_t quadrat; // 0-100
|
||||
uint8_t cuadrado; // 0-100
|
||||
uint8_t molinillo; // 0-100
|
||||
// Suma ha de ser 100, validat en StageLoader
|
||||
};
|
||||
@@ -36,20 +36,20 @@ struct DistribucioEnemics {
|
||||
struct MultiplicadorsDificultat {
|
||||
float velocity; // 0.5-2.0 típic
|
||||
float rotation; // 0.5-2.0 típic
|
||||
float tracking_strength; // 0.0-1.5 (aplicat a Quadrat)
|
||||
float tracking_strength; // 0.0-1.5 (aplicat a Cuadrado)
|
||||
};
|
||||
|
||||
// Metadades del fitxer YAML
|
||||
// Metadades del file YAML
|
||||
struct MetadataStages {
|
||||
std::string version;
|
||||
uint8_t total_stages;
|
||||
std::string descripcio;
|
||||
};
|
||||
|
||||
// Configuració completa d'un stage
|
||||
// Configuración completa de un stage
|
||||
struct StageConfig {
|
||||
uint8_t stage_id; // 1-10
|
||||
uint8_t total_enemics; // 5-15
|
||||
uint8_t total_enemies; // 5-15
|
||||
ConfigSpawn config_spawn;
|
||||
DistribucioEnemics distribucio;
|
||||
MultiplicadorsDificultat multiplicadors;
|
||||
@@ -57,17 +57,17 @@ struct StageConfig {
|
||||
// Validació
|
||||
[[nodiscard]] bool es_valid() const {
|
||||
return stage_id >= 1 && stage_id <= 255 &&
|
||||
total_enemics > 0 && total_enemics <= 15 &&
|
||||
distribucio.pentagon + distribucio.quadrat + distribucio.molinillo == 100;
|
||||
total_enemies > 0 && total_enemies <= 15 &&
|
||||
distribucio.pentagon + distribucio.cuadrado + distribucio.molinillo == 100;
|
||||
}
|
||||
};
|
||||
|
||||
// Configuració completa del sistema (carregada des de YAML)
|
||||
// Configuración completa del sistema (carregada desde YAML)
|
||||
struct StageSystemConfig {
|
||||
MetadataStages metadata;
|
||||
std::vector<StageConfig> stages; // Índex [0] = stage 1
|
||||
|
||||
// Obtenir configuració d'un stage específic
|
||||
// Obtenir configuración de un stage específic
|
||||
[[nodiscard]] const StageConfig* obte_stage(uint8_t stage_id) const {
|
||||
if (stage_id < 1 || stage_id > stages.size()) {
|
||||
return nullptr;
|
||||
@@ -76,9 +76,9 @@ struct StageSystemConfig {
|
||||
}
|
||||
};
|
||||
|
||||
// Constants per missatges de transició
|
||||
// Constants per messages de transición
|
||||
namespace Constants {
|
||||
// Pool de missatges per inici de level (selecció aleatòria)
|
||||
// Pool de messages per start de level (selecció aleatòria)
|
||||
inline constexpr std::array<const char*, 12> MISSATGES_LEVEL_START = {
|
||||
"ORNI ALERT!",
|
||||
"INCOMING ORNIS!",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// stage_loader.cpp - Implementació del carregador de configuració YAML
|
||||
// stage_loader.cpp - Implementació del carregador de configuración YAML
|
||||
// © 2025 Orni Attack
|
||||
|
||||
#include "stage_loader.hpp"
|
||||
@@ -58,7 +58,7 @@ std::unique_ptr<StageSystemConfig> StageLoader::load(const std::string& path) {
|
||||
}
|
||||
|
||||
if (!yaml["stages"].is_sequence()) {
|
||||
std::cerr << "[StageLoader] Error: 'stages' ha de ser una llista" << '\n';
|
||||
std::cerr << "[StageLoader] Error: 'stages' ha de ser una list" << '\n';
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ std::unique_ptr<StageSystemConfig> StageLoader::load(const std::string& path) {
|
||||
config->stages.push_back(stage);
|
||||
}
|
||||
|
||||
// Validar configuració
|
||||
// Validar configuración
|
||||
if (!validar_config(*config)) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -115,7 +115,7 @@ bool StageLoader::parse_stage(const fkyaml::node& yaml, StageConfig& stage) {
|
||||
}
|
||||
|
||||
stage.stage_id = yaml["stage_id"].get_value<uint8_t>();
|
||||
stage.total_enemics = yaml["total_enemies"].get_value<uint8_t>();
|
||||
stage.total_enemies = yaml["total_enemies"].get_value<uint8_t>();
|
||||
|
||||
if (!parse_spawn_config(yaml["spawn_config"], stage.config_spawn)) {
|
||||
return false;
|
||||
@@ -129,7 +129,7 @@ bool StageLoader::parse_stage(const fkyaml::node& yaml, StageConfig& stage) {
|
||||
|
||||
if (!stage.es_valid()) {
|
||||
std::cerr << "[StageLoader] Error: stage " << static_cast<int>(stage.stage_id)
|
||||
<< " no és vàlid" << '\n';
|
||||
<< " no es vàlid" << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -162,18 +162,18 @@ bool StageLoader::parse_spawn_config(const fkyaml::node& yaml, ConfigSpawn& conf
|
||||
|
||||
bool StageLoader::parse_distribution(const fkyaml::node& yaml, DistribucioEnemics& dist) {
|
||||
try {
|
||||
if (!yaml.contains("pentagon") || !yaml.contains("quadrat") ||
|
||||
if (!yaml.contains("pentagon") || !yaml.contains("cuadrado") ||
|
||||
!yaml.contains("molinillo")) {
|
||||
std::cerr << "[StageLoader] Error: enemy_distribution incompleta" << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
dist.pentagon = yaml["pentagon"].get_value<uint8_t>();
|
||||
dist.quadrat = yaml["quadrat"].get_value<uint8_t>();
|
||||
dist.cuadrado = yaml["cuadrado"].get_value<uint8_t>();
|
||||
dist.molinillo = yaml["molinillo"].get_value<uint8_t>();
|
||||
|
||||
// Validar que suma 100
|
||||
int sum = dist.pentagon + dist.quadrat + dist.molinillo;
|
||||
int sum = dist.pentagon + dist.cuadrado + dist.molinillo;
|
||||
if (sum != 100) {
|
||||
std::cerr << "[StageLoader] Error: distribució no suma 100 (suma=" << sum << ")" << '\n';
|
||||
return false;
|
||||
@@ -200,13 +200,13 @@ bool StageLoader::parse_multipliers(const fkyaml::node& yaml, MultiplicadorsDifi
|
||||
|
||||
// Validar rangs raonables
|
||||
if (mult.velocity < 0.1F || mult.velocity > 5.0F) {
|
||||
std::cerr << "[StageLoader] Warning: speed_multiplier fora de rang (0.1-5.0)" << '\n';
|
||||
std::cerr << "[StageLoader] Warning: speed_multiplier fuera de rang (0.1-5.0)" << '\n';
|
||||
}
|
||||
if (mult.rotation < 0.1F || mult.rotation > 5.0F) {
|
||||
std::cerr << "[StageLoader] Warning: rotation_multiplier fora de rang (0.1-5.0)" << '\n';
|
||||
std::cerr << "[StageLoader] Warning: rotation_multiplier fuera de rang (0.1-5.0)" << '\n';
|
||||
}
|
||||
if (mult.tracking_strength < 0.0F || mult.tracking_strength > 2.0F) {
|
||||
std::cerr << "[StageLoader] Warning: tracking_strength fora de rang (0.0-2.0)" << '\n';
|
||||
std::cerr << "[StageLoader] Warning: tracking_strength fuera de rang (0.0-2.0)" << '\n';
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -233,13 +233,13 @@ ModeSpawn StageLoader::parse_spawn_mode(const std::string& mode_str) {
|
||||
|
||||
bool StageLoader::validar_config(const StageSystemConfig& config) {
|
||||
if (config.stages.empty()) {
|
||||
std::cerr << "[StageLoader] Error: cap stage carregat" << '\n';
|
||||
std::cerr << "[StageLoader] Error: sin stage carregat" << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config.stages.size() != config.metadata.total_stages) {
|
||||
std::cerr << "[StageLoader] Warning: nombre de stages (" << config.stages.size()
|
||||
<< ") no coincideix amb metadata.total_stages ("
|
||||
<< ") no coincideix con metadata.total_stages ("
|
||||
<< static_cast<int>(config.metadata.total_stages) << ")" << '\n';
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// stage_loader.hpp - Carregador de configuració YAML
|
||||
// stage_loader.hpp - Carregador de configuración YAML
|
||||
// © 2025 Orni Attack
|
||||
|
||||
#pragma once
|
||||
@@ -13,8 +13,8 @@ namespace StageSystem {
|
||||
|
||||
class StageLoader {
|
||||
public:
|
||||
// Carregar configuració des de fitxer YAML
|
||||
// Retorna nullptr si hi ha errors
|
||||
// Carregar configuración desde file YAML
|
||||
// Retorna nullptr si hay errors
|
||||
static std::unique_ptr<StageSystemConfig> load(const std::string& path);
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// stage_manager.cpp - Implementació del gestor d'stages
|
||||
// stage_manager.cpp - Implementació del gestor de stages
|
||||
// © 2025 Orni Attack
|
||||
|
||||
#include "stage_manager.hpp"
|
||||
@@ -20,7 +20,7 @@ StageManager::StageManager(const StageSystemConfig* config)
|
||||
stage_actual_(1),
|
||||
timer_transicio_(0.0F) {
|
||||
if (config_ == nullptr) {
|
||||
std::cerr << "[StageManager] Error: config és null" << '\n';
|
||||
std::cerr << "[StageManager] Error: config es null" << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ void StageManager::init() {
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
void StageManager::update(float delta_time, bool pausar_spawn) {
|
||||
void StageManager::update(float delta_time, bool pause_spawn) {
|
||||
switch (estat_) {
|
||||
case EstatStage::INIT_HUD:
|
||||
processar_init_hud(delta_time);
|
||||
@@ -44,7 +44,7 @@ void StageManager::update(float delta_time, bool pausar_spawn) {
|
||||
break;
|
||||
|
||||
case EstatStage::PLAYING:
|
||||
processar_playing(delta_time, pausar_spawn);
|
||||
processar_playing(delta_time, pause_spawn);
|
||||
break;
|
||||
|
||||
case EstatStage::LEVEL_COMPLETED:
|
||||
@@ -86,14 +86,14 @@ void StageManager::canviar_estat(EstatStage nou_estat) {
|
||||
size_t index = static_cast<size_t>(std::rand()) % Constants::MISSATGES_LEVEL_START.size();
|
||||
missatge_level_start_actual_ = Constants::MISSATGES_LEVEL_START[index];
|
||||
|
||||
// [NOU] Iniciar música al entrar en LEVEL_START (després de INIT_HUD)
|
||||
// Només si no està sonant ja (per evitar reset en loops posteriors)
|
||||
// [NOU] Iniciar música al entrar en LEVEL_START (después de INIT_HUD)
|
||||
// Solo si no está sonant ya (per evitar reset en loops posteriors)
|
||||
if (Audio::get()->getMusicState() != Audio::MusicState::PLAYING) {
|
||||
Audio::get()->playMusic("game.ogg");
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "[StageManager] Canvi d'state: ";
|
||||
std::cout << "[StageManager] Canvi de state: ";
|
||||
switch (nou_estat) {
|
||||
case EstatStage::INIT_HUD:
|
||||
std::cout << "INIT_HUD";
|
||||
@@ -127,12 +127,12 @@ void StageManager::processar_level_start(float delta_time) {
|
||||
}
|
||||
}
|
||||
|
||||
void StageManager::processar_playing(float delta_time, bool pausar_spawn) {
|
||||
// Update spawn controller (pauses when pausar_spawn = true)
|
||||
void StageManager::processar_playing(float delta_time, bool pause_spawn) {
|
||||
// Update spawn controller (pauses when pause_spawn = true)
|
||||
// Note: The actual enemy array update happens in GameScene::update()
|
||||
// This is just for internal timekeeping
|
||||
(void)delta_time; // Spawn controller is updated externally
|
||||
(void)pausar_spawn; // Passed to spawn_controller_.update() by GameScene
|
||||
(void)pause_spawn; // Passed to spawn_controller_.update() by GameScene
|
||||
}
|
||||
|
||||
void StageManager::processar_level_completed(float delta_time) {
|
||||
@@ -145,7 +145,7 @@ void StageManager::processar_level_completed(float delta_time) {
|
||||
// Loop back to stage 1 after final stage
|
||||
if (stage_actual_ > config_->metadata.total_stages) {
|
||||
stage_actual_ = 1;
|
||||
std::cout << "[StageManager] Totes les stages completades! Tornant a stage 1"
|
||||
std::cout << "[StageManager] Todas las stages completades! Tornant a stage 1"
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
@@ -164,11 +164,11 @@ void StageManager::carregar_stage(uint8_t stage_id) {
|
||||
}
|
||||
|
||||
// Configure spawn controller
|
||||
spawn_controller_.configurar(stage_config);
|
||||
spawn_controller_.iniciar();
|
||||
spawn_controller_.configure(stage_config);
|
||||
spawn_controller_.start();
|
||||
|
||||
std::cout << "[StageManager] Carregat stage " << static_cast<int>(stage_id) << ": "
|
||||
<< static_cast<int>(stage_config->total_enemics) << " enemics" << '\n';
|
||||
<< static_cast<int>(stage_config->total_enemies) << " enemigos" << '\n';
|
||||
}
|
||||
|
||||
} // namespace StageSystem
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// stage_manager.hpp - Gestor d'state i progressió d'stages
|
||||
// stage_manager.hpp - Gestor de state i progressió de stages
|
||||
// © 2025 Orni Attack
|
||||
|
||||
#pragma once
|
||||
@@ -13,7 +13,7 @@ namespace StageSystem {
|
||||
|
||||
// Estats del stage system
|
||||
enum class EstatStage {
|
||||
INIT_HUD, // Animació inicial del HUD (3s)
|
||||
INIT_HUD, // Animación inicial del HUD (3s)
|
||||
LEVEL_START, // Pantalla "ENEMY INCOMING" (3s)
|
||||
PLAYING, // Gameplay normal
|
||||
LEVEL_COMPLETED // Pantalla "GOOD JOB COMMANDER!" (3s)
|
||||
@@ -25,7 +25,7 @@ class StageManager {
|
||||
|
||||
// Lifecycle
|
||||
void init(); // Reset to stage 1
|
||||
void update(float delta_time, bool pausar_spawn = false);
|
||||
void update(float delta_time, bool pause_spawn = false);
|
||||
|
||||
// Stage progression
|
||||
void stage_completat(); // Call when all enemies destroyed
|
||||
@@ -39,8 +39,8 @@ class StageManager {
|
||||
[[nodiscard]] const std::string& get_missatge_level_start() const { return missatge_level_start_actual_; }
|
||||
|
||||
// Spawn control (delegate to SpawnController)
|
||||
SpawnController& get_spawn_controller() { return spawn_controller_; }
|
||||
[[nodiscard]] const SpawnController& get_spawn_controller() const { return spawn_controller_; }
|
||||
SpawnController& getSpawnController() { return spawn_controller_; }
|
||||
[[nodiscard]] const SpawnController& getSpawnController() const { return spawn_controller_; }
|
||||
|
||||
private:
|
||||
const StageSystemConfig* config_; // Non-owning pointer
|
||||
@@ -55,7 +55,7 @@ class StageManager {
|
||||
void canviar_estat(EstatStage nou_estat);
|
||||
void processar_init_hud(float delta_time);
|
||||
void processar_level_start(float delta_time);
|
||||
void processar_playing(float delta_time, bool pausar_spawn);
|
||||
void processar_playing(float delta_time, bool pause_spawn);
|
||||
void processar_level_completed(float delta_time);
|
||||
void carregar_stage(uint8_t stage_id);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// ship_animator.cpp - Implementació del sistema d'animació de naus
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// ship_animator.cpp - Implementació del sistema de animación de naves
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include "ship_animator.hpp"
|
||||
|
||||
@@ -18,9 +18,9 @@ ShipAnimator::ShipAnimator(SDL_Renderer* renderer)
|
||||
}
|
||||
|
||||
void ShipAnimator::init() {
|
||||
// Carregar formes de naus amb perspectiva pre-calculada
|
||||
auto forma_p1 = Graphics::ShapeLoader::load("ship_perspective.shp"); // Perspectiva esquerra
|
||||
auto forma_p2 = Graphics::ShapeLoader::load("ship2_perspective.shp"); // Perspectiva dreta
|
||||
// Carregar formes de naves con perspectiva pre-calculada
|
||||
auto forma_p1 = Graphics::ShapeLoader::load("ship_perspective.shp"); // Perspectiva izquierda
|
||||
auto forma_p2 = Graphics::ShapeLoader::load("ship2_perspective.shp"); // Perspectiva derecha
|
||||
|
||||
// Configurar ship P1
|
||||
ships_[0].player_id = 1;
|
||||
@@ -60,14 +60,14 @@ void ShipAnimator::draw() const {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Renderitzar ship (perspectiva ja incorporada a la shape)
|
||||
// Renderizar ship (perspectiva ya incorporada a la shape)
|
||||
Rendering::render_shape(
|
||||
renderer_,
|
||||
ship.shape,
|
||||
ship.current_position,
|
||||
0.0F, // angle (rotació 2D no utilitzada)
|
||||
0.0F, // angle (rotación 2D no utilitzada)
|
||||
ship.current_scale,
|
||||
1.0F, // progress (sempre visible)
|
||||
1.0F, // progress (siempre visible)
|
||||
1.0F // brightness (brightness màxima)
|
||||
);
|
||||
}
|
||||
@@ -76,14 +76,14 @@ void ShipAnimator::draw() const {
|
||||
void ShipAnimator::start_entry_animation() {
|
||||
using namespace Defaults::Title::Ships;
|
||||
|
||||
// Configurar ship P1 per a l'animació d'entrada
|
||||
// Configurar ship P1 para l'animación de entrada
|
||||
ships_[0].state = ShipState::ENTERING;
|
||||
ships_[0].state_time = 0.0F;
|
||||
ships_[0].initial_position = calcular_posicio_fora_pantalla(CLOCK_8_ANGLE);
|
||||
ships_[0].current_position = ships_[0].initial_position;
|
||||
ships_[0].current_scale = ships_[0].initial_scale;
|
||||
|
||||
// Configurar ship P2 per a l'animació d'entrada
|
||||
// Configurar ship P2 para l'animación de entrada
|
||||
ships_[1].state = ShipState::ENTERING;
|
||||
ships_[1].state_time = 0.0F;
|
||||
ships_[1].initial_position = calcular_posicio_fora_pantalla(CLOCK_4_ANGLE);
|
||||
@@ -92,38 +92,38 @@ void ShipAnimator::start_entry_animation() {
|
||||
}
|
||||
|
||||
void ShipAnimator::trigger_exit_animation() {
|
||||
// Configurar ambdues naus per a l'animació de sortida
|
||||
// Configurar ambdues naves para l'animación de salida
|
||||
for (auto& ship : ships_) {
|
||||
// Canviar state a EXITING
|
||||
ship.state = ShipState::EXITING;
|
||||
ship.state_time = 0.0F;
|
||||
|
||||
// Preservar posició actual (pot estar a mig camí si START es prem durant ENTERING)
|
||||
// Preservar posición actual (pot estar a mig camí si START es prem durante ENTERING)
|
||||
ship.initial_position = ship.current_position;
|
||||
|
||||
// La scale objectiu es preserva per a calcular la interpolació
|
||||
// (current_scale pot ser diferent si està en ENTERING)
|
||||
// La scale objetivo es preserva para calcular la interpolació
|
||||
// (current_scale pot ser diferent si está en ENTERING)
|
||||
}
|
||||
}
|
||||
|
||||
void ShipAnimator::skip_to_floating_state() {
|
||||
// Posar ambdues naus directament en state FLOATING
|
||||
// Posar ambdues naves directament en state FLOATING
|
||||
for (auto& ship : ships_) {
|
||||
ship.state = ShipState::FLOATING;
|
||||
ship.state_time = 0.0F;
|
||||
ship.oscillation_phase = 0.0F;
|
||||
|
||||
// Posar en posició objectiu (sense animació)
|
||||
// Posar en posición objetivo (sin animación)
|
||||
ship.current_position = ship.target_position;
|
||||
ship.current_scale = ship.target_scale;
|
||||
|
||||
// NO establir visibilitat aquí - ja ho fa el caller
|
||||
// (evita fer visibles ambdues naus quan només una ha premut START)
|
||||
// NO establir visibilitat aquí - ya ho hace el caller
|
||||
// (evita fer visibles ambdues naves cuando solo una ha premut START)
|
||||
}
|
||||
}
|
||||
|
||||
bool ShipAnimator::is_visible() const {
|
||||
// Retorna true si almenys una ship és visible
|
||||
// Retorna true si almenys una ship es visible
|
||||
for (const auto& ship : ships_) {
|
||||
if (ship.visible) {
|
||||
return true;
|
||||
@@ -136,16 +136,16 @@ void ShipAnimator::trigger_exit_animation_for_player(int player_id) {
|
||||
// Trobar la ship del player especificat
|
||||
for (auto& ship : ships_) {
|
||||
if (ship.player_id == player_id) {
|
||||
// Canviar state a EXITING només per aquesta ship
|
||||
// Canviar state a EXITING solo per esta ship
|
||||
ship.state = ShipState::EXITING;
|
||||
ship.state_time = 0.0F;
|
||||
|
||||
// Preservar posició actual (pot estar a mig camí si START es prem durant ENTERING)
|
||||
// Preservar posición actual (pot estar a mig camí si START es prem durante ENTERING)
|
||||
ship.initial_position = ship.current_position;
|
||||
|
||||
// La scale objectiu es preserva per a calcular la interpolació
|
||||
// (current_scale pot ser diferent si està en ENTERING)
|
||||
break; // Només una ship per player
|
||||
// La scale objetivo es preserva para calcular la interpolació
|
||||
// (current_scale pot ser diferent si está en ENTERING)
|
||||
break; // Solo una ship per player
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,67 +157,67 @@ void ShipAnimator::set_visible(bool visible) {
|
||||
}
|
||||
|
||||
bool ShipAnimator::is_animation_complete() const {
|
||||
// Comprovar si totes les naus són invisibles (han completat l'animació de sortida)
|
||||
// Comprovar si todas las naves són invisibles (han completat l'animación de salida)
|
||||
for (const auto& ship : ships_) {
|
||||
if (ship.visible) {
|
||||
return false; // Encara hi ha alguna ship visible
|
||||
return false; // Aún hay alguna ship visible
|
||||
}
|
||||
}
|
||||
return true; // Totes les naus són invisibles
|
||||
return true; // Todas las naves són invisibles
|
||||
}
|
||||
|
||||
// Mètodes d'animació (stubs)
|
||||
// Métodos de animación (stubs)
|
||||
void ShipAnimator::actualitzar_entering(TitleShip& ship, float delta_time) {
|
||||
using namespace Defaults::Title::Ships;
|
||||
|
||||
ship.state_time += delta_time;
|
||||
|
||||
// Esperar al delay abans de començar l'animació
|
||||
// Esperar al delay antes de començar l'animación
|
||||
if (ship.state_time < ship.entry_delay) {
|
||||
// Encara en delay: la ship es queda fora de pantalla (posició inicial)
|
||||
// Aún en delay: la ship es queda fuera de pantalla (posición inicial)
|
||||
ship.current_position = ship.initial_position;
|
||||
ship.current_scale = ship.initial_scale;
|
||||
return;
|
||||
}
|
||||
|
||||
// Càlcul del progrés (restant el delay)
|
||||
// Cálculo del progrés (restant el delay)
|
||||
float elapsed = ship.state_time - ship.entry_delay;
|
||||
float progress = std::min(1.0F, elapsed / ENTRY_DURATION);
|
||||
|
||||
// Aplicar easing (ease_out_quad per arribada suau)
|
||||
float eased_progress = Easing::ease_out_quad(progress);
|
||||
|
||||
// Lerp posició (inicial → objectiu)
|
||||
// Lerp posición (inicial → objetivo)
|
||||
ship.current_position.x = Easing::lerp(ship.initial_position.x, ship.target_position.x, eased_progress);
|
||||
ship.current_position.y = Easing::lerp(ship.initial_position.y, ship.target_position.y, eased_progress);
|
||||
|
||||
// Lerp scale (gran → normal)
|
||||
// Lerp scale (grande → normal)
|
||||
ship.current_scale = Easing::lerp(ship.initial_scale, ship.target_scale, eased_progress);
|
||||
|
||||
// Transicionar a FLOATING quan completi
|
||||
// Transicionar a FLOATING cuando completi
|
||||
if (elapsed >= ENTRY_DURATION) {
|
||||
ship.state = ShipState::FLOATING;
|
||||
ship.state_time = 0.0F;
|
||||
ship.oscillation_phase = 0.0F; // Reiniciar fase d'oscil·lació
|
||||
ship.oscillation_phase = 0.0F; // Reiniciar fase de oscil·lació
|
||||
}
|
||||
}
|
||||
|
||||
void ShipAnimator::actualitzar_floating(TitleShip& ship, float delta_time) {
|
||||
using namespace Defaults::Title::Ships;
|
||||
|
||||
// Actualitzar time i fase d'oscil·lació
|
||||
// Actualitzar time i fase de oscil·lació
|
||||
ship.state_time += delta_time;
|
||||
ship.oscillation_phase += delta_time;
|
||||
|
||||
// Oscil·lació sinusoïdal X/Y (paràmetres específics per ship)
|
||||
// Oscil·lació sinusoïdal X/Y (parámetros específics per ship)
|
||||
float offset_x = ship.amplitude_x * std::sin(2.0F * Defaults::Math::PI * ship.frequency_x * ship.oscillation_phase);
|
||||
float offset_y = ship.amplitude_y * std::sin((2.0F * Defaults::Math::PI * ship.frequency_y * ship.oscillation_phase) + FLOAT_PHASE_OFFSET);
|
||||
|
||||
// Aplicar oscil·lació a la posició objectiu
|
||||
// Aplicar oscil·lació a la posición objetivo
|
||||
ship.current_position.x = ship.target_position.x + offset_x;
|
||||
ship.current_position.y = ship.target_position.y + offset_y;
|
||||
|
||||
// Escala constant (sense "breathing" per ara)
|
||||
// Escala constant (sin "breathing" per ara)
|
||||
ship.current_scale = ship.target_scale;
|
||||
}
|
||||
|
||||
@@ -229,27 +229,27 @@ void ShipAnimator::actualitzar_exiting(TitleShip& ship, float delta_time) {
|
||||
// Calcular progrés (0.0 → 1.0)
|
||||
float progress = std::min(1.0F, ship.state_time / EXIT_DURATION);
|
||||
|
||||
// Aplicar easing (ease_in_quad per acceleració cap al point de fuga)
|
||||
// Aplicar easing (ease_in_quad per aceleración hacia el point de fuga)
|
||||
float eased_progress = Easing::ease_in_quad(progress);
|
||||
|
||||
// Vec2 de fuga (centre del starfield)
|
||||
// Vec2 de fuga (centro del starfield)
|
||||
constexpr Vec2 punt_fuga{.x = VANISHING_POINT_X, .y = VANISHING_POINT_Y};
|
||||
|
||||
// Lerp posició cap al point de fuga (preservar posició inicial actual)
|
||||
// Nota: initial_position conté la posició on estava quan es va activar EXITING
|
||||
// Lerp posición hacia el point de fuga (preservar posición inicial actual)
|
||||
// Nota: initial_position conté la posición on estava cuando es va activar EXITING
|
||||
ship.current_position.x = Easing::lerp(ship.initial_position.x, punt_fuga.x, eased_progress);
|
||||
ship.current_position.y = Easing::lerp(ship.initial_position.y, punt_fuga.y, eased_progress);
|
||||
|
||||
// Escala redueix a 0 (simula Z → infinit)
|
||||
ship.current_scale = ship.target_scale * (1.0F - eased_progress);
|
||||
|
||||
// Marcar invisible quan l'animació completi
|
||||
// Marcar invisible cuando l'animación completi
|
||||
if (progress >= 1.0F) {
|
||||
ship.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Configuració
|
||||
// Configuración
|
||||
void ShipAnimator::configurar_nau_p1(TitleShip& ship) {
|
||||
using namespace Defaults::Title::Ships;
|
||||
|
||||
@@ -260,9 +260,9 @@ void ShipAnimator::configurar_nau_p1(TitleShip& ship) {
|
||||
// Posicions (clock 8, bottom-left)
|
||||
ship.target_position = {.x = P1_TARGET_X(), .y = P1_TARGET_Y()};
|
||||
|
||||
// Calcular posició inicial (fora de pantalla)
|
||||
// Calcular posición inicial (fuera de pantalla)
|
||||
ship.initial_position = calcular_posicio_fora_pantalla(CLOCK_8_ANGLE);
|
||||
ship.current_position = ship.initial_position; // Començar fora de pantalla
|
||||
ship.current_position = ship.initial_position; // Començar fuera de pantalla
|
||||
|
||||
// Escales
|
||||
ship.target_scale = FLOATING_SCALE;
|
||||
@@ -272,10 +272,10 @@ void ShipAnimator::configurar_nau_p1(TitleShip& ship) {
|
||||
// Flotació
|
||||
ship.oscillation_phase = 0.0F;
|
||||
|
||||
// Paràmetres d'entrada
|
||||
// Parámetros de entrada
|
||||
ship.entry_delay = P1_ENTRY_DELAY;
|
||||
|
||||
// Paràmetres d'oscil·lació específics P1
|
||||
// Parámetros de oscil·lació específics P1
|
||||
ship.amplitude_x = FLOAT_AMPLITUDE_X;
|
||||
ship.amplitude_y = FLOAT_AMPLITUDE_Y;
|
||||
ship.frequency_x = FLOAT_FREQUENCY_X_BASE * P1_FREQUENCY_MULTIPLIER;
|
||||
@@ -295,9 +295,9 @@ void ShipAnimator::configurar_nau_p2(TitleShip& ship) {
|
||||
// Posicions (clock 4, bottom-right)
|
||||
ship.target_position = {.x = P2_TARGET_X(), .y = P2_TARGET_Y()};
|
||||
|
||||
// Calcular posició inicial (fora de pantalla)
|
||||
// Calcular posición inicial (fuera de pantalla)
|
||||
ship.initial_position = calcular_posicio_fora_pantalla(CLOCK_4_ANGLE);
|
||||
ship.current_position = ship.initial_position; // Començar fora de pantalla
|
||||
ship.current_position = ship.initial_position; // Començar fuera de pantalla
|
||||
|
||||
// Escales
|
||||
ship.target_scale = FLOATING_SCALE;
|
||||
@@ -307,10 +307,10 @@ void ShipAnimator::configurar_nau_p2(TitleShip& ship) {
|
||||
// Flotació
|
||||
ship.oscillation_phase = 0.0F;
|
||||
|
||||
// Paràmetres d'entrada
|
||||
// Parámetros de entrada
|
||||
ship.entry_delay = P2_ENTRY_DELAY;
|
||||
|
||||
// Paràmetres d'oscil·lació específics P2
|
||||
// Parámetros de oscil·lació específics P2
|
||||
ship.amplitude_x = FLOAT_AMPLITUDE_X;
|
||||
ship.amplitude_y = FLOAT_AMPLITUDE_Y;
|
||||
ship.frequency_x = FLOAT_FREQUENCY_X_BASE * P2_FREQUENCY_MULTIPLIER;
|
||||
@@ -324,7 +324,7 @@ Vec2 ShipAnimator::calcular_posicio_fora_pantalla(float angle_rellotge) const {
|
||||
using namespace Defaults::Title::Ships;
|
||||
|
||||
// Convertir angle del rellotge a radians (per exemple: 240° per clock 8)
|
||||
// Calcular posició en direcció radial des del centre, però més lluny
|
||||
// Calcular posición en direcció radial des del centro, pero més lluny
|
||||
// ENTRY_OFFSET es calcula automàticament: (SHIP_MAX_RADIUS * ENTRY_SCALE_START) + ENTRY_OFFSET_MARGIN
|
||||
float extended_radius = CLOCK_RADIUS + ENTRY_OFFSET;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// ship_animator.hpp - Sistema d'animació de naus per a l'escena de títol
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// ship_animator.hpp - Sistema de animación de naves para l'escena de título
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
|
||||
namespace Title {
|
||||
|
||||
// Estats de l'animació de la ship
|
||||
// Estats de l'animación de la ship
|
||||
enum class ShipState {
|
||||
ENTERING, // Entrant des de fora de pantalla
|
||||
FLOATING, // Flotant en posició estàtica
|
||||
EXITING // Volant cap al point de fuga
|
||||
ENTERING, // Entrant desde fuera de pantalla
|
||||
FLOATING, // Flotante en posición estàtica
|
||||
EXITING // Volant hacia el point de fuga
|
||||
};
|
||||
|
||||
// Dades d'una ship individual al títol
|
||||
// Dades de una ship individual al título
|
||||
struct TitleShip {
|
||||
// Identificació
|
||||
int player_id; // 1 o 2
|
||||
@@ -30,22 +30,22 @@ struct TitleShip {
|
||||
float state_time; // Temps acumulat en l'state actual
|
||||
|
||||
// Posicions
|
||||
Vec2 initial_position; // Posició d'inici (fora de pantalla per ENTERING)
|
||||
Vec2 target_position; // Posició objectiu (rellotge 8 o 4)
|
||||
Vec2 current_position; // Posició interpolada actual
|
||||
Vec2 initial_position; // Posición de start (fuera de pantalla per ENTERING)
|
||||
Vec2 target_position; // Posición objetivo (rellotge 8 o 4)
|
||||
Vec2 current_position; // Posición interpolada actual
|
||||
|
||||
// Escales (simulació eix Z)
|
||||
float initial_scale; // Escala d'inici (més gran = més a prop)
|
||||
float target_scale; // Escala objectiu (mida flotació)
|
||||
float initial_scale; // Escala de start (més grande = més a prop)
|
||||
float target_scale; // Escala objetivo (mida flotació)
|
||||
float current_scale; // Escala interpolada actual
|
||||
|
||||
// Flotació
|
||||
float oscillation_phase; // Acumulador de fase per moviment sinusoïdal
|
||||
float oscillation_phase; // Acumulador de fase per movement sinusoïdal
|
||||
|
||||
// Paràmetres d'entrada
|
||||
float entry_delay; // Delay abans d'entrar (0.0 per P1, 0.5 per P2)
|
||||
// Parámetros de entrada
|
||||
float entry_delay; // Delay antes de entrar (0.0 per P1, 0.5 per P2)
|
||||
|
||||
// Paràmetres d'oscil·lació per ship
|
||||
// Parámetros de oscil·lació per ship
|
||||
float amplitude_x;
|
||||
float amplitude_y;
|
||||
float frequency_x;
|
||||
@@ -58,7 +58,7 @@ struct TitleShip {
|
||||
bool visible;
|
||||
};
|
||||
|
||||
// Gestor d'animació de naus per a l'escena de títol
|
||||
// Gestor de animación de naves para l'escena de título
|
||||
class ShipAnimator {
|
||||
public:
|
||||
explicit ShipAnimator(SDL_Renderer* renderer);
|
||||
@@ -68,27 +68,27 @@ class ShipAnimator {
|
||||
void update(float delta_time);
|
||||
void draw() const;
|
||||
|
||||
// Control d'state (cridat per TitleScene)
|
||||
// Control de state (cridat per TitleScene)
|
||||
void start_entry_animation();
|
||||
void trigger_exit_animation(); // Anima totes les naus
|
||||
void trigger_exit_animation_for_player(int player_id); // Anima només una ship (P1=1, P2=2)
|
||||
void skip_to_floating_state(); // Salta directament a FLOATING sense animació
|
||||
void trigger_exit_animation(); // Anima todas las naves
|
||||
void trigger_exit_animation_for_player(int player_id); // Anima solo una ship (P1=1, P2=2)
|
||||
void skip_to_floating_state(); // Salta directament a FLOATING sin animación
|
||||
|
||||
// Control de visibilitat
|
||||
void set_visible(bool visible);
|
||||
[[nodiscard]] bool is_animation_complete() const;
|
||||
[[nodiscard]] bool is_visible() const; // Comprova si alguna ship és visible
|
||||
[[nodiscard]] bool is_visible() const; // Comprova si alguna ship es visible
|
||||
|
||||
private:
|
||||
SDL_Renderer* renderer_;
|
||||
std::array<TitleShip, 2> ships_; // Naus P1 i P2
|
||||
std::array<TitleShip, 2> ships_; // Naves P1 i P2
|
||||
|
||||
// Mètodes d'animació
|
||||
// Métodos de animación
|
||||
void actualitzar_entering(TitleShip& ship, float delta_time);
|
||||
void actualitzar_floating(TitleShip& ship, float delta_time);
|
||||
void actualitzar_exiting(TitleShip& ship, float delta_time);
|
||||
|
||||
// Configuració
|
||||
// Configuración
|
||||
void configurar_nau_p1(TitleShip& ship);
|
||||
void configurar_nau_p2(TitleShip& ship);
|
||||
[[nodiscard]] Vec2 calcular_posicio_fora_pantalla(float angle_rellotge) const;
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
// main.cpp - Vec2 d'entrada del joc Asteroides
|
||||
// © 1999 Visente i Sergi (versió Pascal)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// main.cpp - Vec2 de entrada del juego Asteroides
|
||||
// © 1999 Visente i Sergi (versión Pascal)
|
||||
// © 2025 Port a C++20 con SDL3
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -11,9 +11,9 @@ int main(int argc, char* argv[]) {
|
||||
// Convertir arguments a std::vector<std::string>
|
||||
std::vector<std::string> args(argv, argv + argc);
|
||||
|
||||
// Crear director (inicialitza sistema, opcions, configuració)
|
||||
// Crear director (inicialitza sistema, opciones, configuración)
|
||||
Director director(args);
|
||||
|
||||
// Executar bucle principal del joc
|
||||
// Executar bucle principal del juego
|
||||
return director.run();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user