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:
2026-05-19 12:12:30 +02:00
parent 7ee359b910
commit bf83f161b0
71 changed files with 1142 additions and 1148 deletions
+1 -1
View File
@@ -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;
+2 -2
View File
@@ -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 -1
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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)
+6 -6
View File
@@ -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}) {}
+6 -6
View File
@@ -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};
}
}
+7 -7
View File
@@ -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ó)
+6 -6
View File
@@ -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;
}
+4 -4
View File
@@ -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);
+27 -27
View File
@@ -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
);
}
+24 -24
View File
@@ -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)
};
+9 -9
View File
@@ -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 -1
View File
@@ -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
+6 -6
View File
@@ -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;
}
+5 -5
View File
@@ -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);
+4 -4
View File
@@ -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;
+3 -3
View File
@@ -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,
+2 -2
View File
@@ -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);
}
+3 -3
View File
@@ -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"
+4 -4
View File
@@ -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
+31 -31
View File
@@ -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();
}
+12 -15
View File
@@ -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
+20 -20
View File
@@ -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
+10 -10
View File
@@ -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,
+6 -6
View File
@@ -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();
}
+4 -4
View File
@@ -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);
+11 -11
View File
@@ -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;
}
+4 -4
View File
@@ -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);
};
+16 -16
View File
@@ -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());
+10 -10
View File
@@ -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);
+27 -27
View File
@@ -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;
+11 -11
View File
@@ -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)
}
};
+2 -2
View File
@@ -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
+24 -24
View File
@@ -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
+7 -7
View File
@@ -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();
+2 -2
View File
@@ -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
+116 -116
View File
@@ -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"
+5 -5
View File
@@ -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);
+12 -12
View File
@@ -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
+52 -52
View File
@@ -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;
+14 -14
View File
@@ -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;
};
+8 -8
View File
@@ -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;
+11 -11
View File
@@ -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_;
+12 -12
View File
@@ -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;
+5 -5
View File
@@ -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_; }
+24 -24
View File
@@ -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;
}
+13 -13
View File
@@ -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
+19 -19
View File
@@ -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;
+7 -7
View File
@@ -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
View File
@@ -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 -6
View File
@@ -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
+89 -89
View File
@@ -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
+17 -20
View File
@@ -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
+50 -50
View File
@@ -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 {
+20 -20
View File
@@ -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;
};
+70 -70
View File
@@ -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);
+31 -31
View File
@@ -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
+19 -19
View File
@@ -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!",
+13 -13
View File
@@ -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';
}
+3 -3
View File
@@ -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:
+14 -14
View File
@@ -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
+6 -6
View File
@@ -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);
};
+54 -54
View File
@@ -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;
+25 -25
View File
@@ -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
View File
@@ -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();
}