From 624039e00d7400999cf3d5074a3c70c4c691095f Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Fri, 28 Nov 2025 21:07:36 +0100 Subject: [PATCH] treballant en el LOGO --- Asteroids.ico | Bin 2238 -> 0 bytes CMakeLists.txt | 1 + Makefile | 1 + asteroids | Bin 33200 -> 0 bytes data/shapes/letra_a.shp | 9 + data/shapes/letra_e.shp | 9 + data/shapes/letra_g.shp | 9 + data/shapes/letra_i.shp | 9 + data/shapes/letra_j.shp | 9 + data/shapes/letra_l.shp | 9 + data/shapes/letra_m.shp | 9 + data/shapes/letra_s.shp | 9 + jailgames.svg | 15 ++ source/game/escenes/escena_joc.cpp | 25 +- source/game/escenes/escena_logo.cpp | 138 +++++++++-- source/game/escenes/escena_logo.hpp | 25 +- tools/svg_to_shp.py | 340 ++++++++++++++++++++++++++++ 17 files changed, 573 insertions(+), 44 deletions(-) delete mode 100755 Asteroids.ico delete mode 100755 asteroids create mode 100644 data/shapes/letra_a.shp create mode 100644 data/shapes/letra_e.shp create mode 100644 data/shapes/letra_g.shp create mode 100644 data/shapes/letra_i.shp create mode 100644 data/shapes/letra_j.shp create mode 100644 data/shapes/letra_l.shp create mode 100644 data/shapes/letra_m.shp create mode 100644 data/shapes/letra_s.shp create mode 100644 jailgames.svg create mode 100755 tools/svg_to_shp.py diff --git a/Asteroids.ico b/Asteroids.ico deleted file mode 100755 index ce406823ab4688734b541b5f6ca2e5a2a4105a82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2238 zcmc(ePiP!<6vsa^yV*^$3n>jvR*g8;gF&N|D%~J~+F097Ta)om4bmmaAvY1iB1Kfp z!~`!EZLyUcVq3J(Qk6gmO)0{(Id}*jiWEE;tdvwds1#Y5CY03gZ)ThB+T9lP;M@J} z{NDS#_kQoa`7K!bI1c))=Ttqk0PR{b@vN4y-x6CJvt$e$e^dq7 zEbRBN94GaFb>>5TrNalVs~V zeb|;NPAgd7OPxhNj~yhq(tzLm5{&`W`2t%NF1I!U=6RgL?;BxTlEXnC`+S?GCGkb* zu#S=DRdA$Bw(}5^JcGM*Q+xx5tet$JL_yO|{B|V_o>NcaXY%l3KO=4rCl2-Ewr^K- zABV5>v#AAC`%-`2aA=o0_<2(0z){nL07Dg4QL7&y*FU1#r z&}J7SZ+KkIXmr7B=sz@_0JX%X0*omiv+Cc&4G*?)9&mNO2g?KUe^6s8%6A3|I$z@K z5DT|CX&!AKT~?lS$p+_7%iN_!biS>c!wc!iN3xDQCrPmlQ}14!>@dVVSh=Y4*5O>7 zgAdimZedCOUCrnMTvtE7`Z@lD^e?4fPva}MlgTsic8XyVjCn9LslGlnk?Pm;$aTWx zgyvy}=e6Kmlhf;3x+8dT?q`mZR;%i1)WNrTEW!yq8tMe7+u88}) zctO|TClT|?jO0$GnbhlWm(6`k(Kw~&g_O>V=F8^DkI(cxsx{~7THMfPkCy6RP@ksN z)lemV4@uPER%CBTB$kpoeQUgW{4HFo z{*Z@LsTyx^NNdEeQN!!%k|p12kB}#8dz5&xmdkBk%Ax;pxs>rRh3-r_j_OnPNX$Q> z0#|Z#;VN+juY$|DusNkNL0Nqf{)a;uFV$F?pbD>W_&2;fLACh*%*zs({Ec@=B9$tA R#qXevjj7wxV5a_m%HN!+>aPF* diff --git a/CMakeLists.txt b/CMakeLists.txt index a8e9125..eef6346 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ configure_file(${CMAKE_SOURCE_DIR}/source/project.h.in ${CMAKE_BINARY_DIR}/proje set(APP_SOURCES source/main.cpp source/core/system/director.cpp + source/core/system/global_events.cpp source/core/rendering/sdl_manager.cpp source/core/rendering/line_renderer.cpp source/core/rendering/color_oscillator.cpp diff --git a/Makefile b/Makefile index bd4f719..5522d38 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,7 @@ endif APP_SOURCES := \ source/main.cpp \ source/core/system/director.cpp \ + source/core/system/global_events.cpp \ source/core/rendering/sdl_manager.cpp \ source/core/rendering/line_renderer.cpp \ source/core/rendering/color_oscillator.cpp \ diff --git a/asteroids b/asteroids deleted file mode 100755 index 9f0079bd2b05493e2e36cbe2f7047dfe0994b219..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33200 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 LF(pGF16BS5 + + + + + + + + + + + + + + diff --git a/source/game/escenes/escena_joc.cpp b/source/game/escenes/escena_joc.cpp index 41122ab..0344688 100644 --- a/source/game/escenes/escena_joc.cpp +++ b/source/game/escenes/escena_joc.cpp @@ -4,6 +4,7 @@ #include "escena_joc.hpp" #include "../../core/system/gestor_escenes.hpp" +#include "../../core/system/global_events.hpp" #include #include #include @@ -49,29 +50,13 @@ void EscenaJoc::executar() { continue; } - // Tecles globals de finestra (F1/F2/F3) - if (event.type == SDL_EVENT_KEY_DOWN) { - switch (event.key.key) { - case SDLK_F1: - sdl_.decreaseWindowSize(); - continue; - case SDLK_F2: - sdl_.increaseWindowSize(); - continue; - case SDLK_F3: - sdl_.toggleFullscreen(); - continue; - } + // Events globals (F1/F2/F3/ESC/QUIT) + if (GlobalEvents::handle(event, sdl_)) { + continue; } - // Processament normal del joc + // Processament específic del joc (SPACE per disparar) processar_input(event); - - // Detectar tancament de finestra o ESC - if (event.type == SDL_EVENT_QUIT || - (event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_ESCAPE)) { - GestorEscenes::actual = GestorEscenes::Escena::EIXIR; - } } // Actualitzar física del joc amb delta_time real diff --git a/source/game/escenes/escena_logo.cpp b/source/game/escenes/escena_logo.cpp index 1757791..5c22b1c 100644 --- a/source/game/escenes/escena_logo.cpp +++ b/source/game/escenes/escena_logo.cpp @@ -3,11 +3,17 @@ #include "escena_logo.hpp" #include "../../core/system/gestor_escenes.hpp" +#include "../../core/system/global_events.hpp" +#include "../../core/graphics/shape_loader.hpp" +#include "../../core/rendering/shape_renderer.hpp" #include +#include +#include EscenaLogo::EscenaLogo(SDLManager& sdl) : sdl_(sdl), temps_acumulat_(0.0f) { std::cout << "Escena Logo: Inicialitzant...\n"; + inicialitzar_lletres(); } void EscenaLogo::executar() { @@ -32,34 +38,21 @@ void EscenaLogo::executar() { continue; } - // Tecles globals de finestra (F1/F2/F3) - if (event.type == SDL_EVENT_KEY_DOWN) { - switch (event.key.key) { - case SDLK_F1: - sdl_.decreaseWindowSize(); - continue; - case SDLK_F2: - sdl_.increaseWindowSize(); - continue; - case SDLK_F3: - sdl_.toggleFullscreen(); - continue; - } + // Events globals (F1/F2/F3/ESC/QUIT) + if (GlobalEvents::handle(event, sdl_)) { + continue; } - // Processar events de l'escena + // Processar events de l'escena (qualsevol tecla/clic salta al joc) processar_events(event); - - // ESC o tancar finestra = eixir - if (event.type == SDL_EVENT_QUIT || - (event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_ESCAPE)) { - GestorEscenes::actual = GestorEscenes::Escena::EIXIR; - } } // Actualitzar lògica actualitzar(delta_time); + // Actualitzar colors oscil·lats (efecte verd global) + sdl_.updateColors(delta_time); + // Dibuixar dibuixar(); } @@ -67,18 +60,117 @@ void EscenaLogo::executar() { std::cout << "Escena Logo: Finalitzant...\n"; } +void EscenaLogo::inicialitzar_lletres() { + using namespace Graphics; + + // Llista de fitxers .shp (A repetida per a les dues A's) + std::vector fitxers = { + "letra_j.shp", "letra_a.shp", "letra_i.shp", "letra_l.shp", + "letra_g.shp", "letra_a.shp", "letra_m.shp", "letra_e.shp", "letra_s.shp" + }; + + // Pas 1: Carregar totes les formes i calcular amplades + float ancho_total = 0.0f; + + for (const auto& fitxer : fitxers) { + auto forma = ShapeLoader::load(fitxer); + if (!forma || !forma->es_valida()) { + std::cerr << "[EscenaLogo] Error carregant " << fitxer << std::endl; + continue; + } + + // Calcular bounding box de la forma (trobar ancho) + float min_x = FLT_MAX; + float max_x = -FLT_MAX; + + for (const auto& prim : forma->get_primitives()) { + for (const auto& punt : prim.points) { + min_x = std::min(min_x, punt.x); + max_x = std::max(max_x, punt.x); + } + } + + float ancho = max_x - min_x; + + lletres_.push_back({ + forma, + {0.0f, 0.0f}, // Posició es calcularà després + ancho + }); + + ancho_total += ancho; + } + + // Pas 2: Afegir espaiat entre lletres + ancho_total += ESPAI_ENTRE_LLETRES * (lletres_.size() - 1); + + // Pas 3: Calcular posició inicial (centrat horitzontal) + constexpr float PANTALLA_ANCHO = 640.0f; + constexpr float PANTALLA_ALTO = 480.0f; + + float x_inicial = (PANTALLA_ANCHO - ancho_total) / 2.0f; + float y_centre = PANTALLA_ALTO / 2.0f; + + // Pas 4: Assignar posicions a cada lletra + float x_actual = x_inicial; + + for (auto& lletra : lletres_) { + // Centre de la lletra en pantalla + lletra.posicio.x = x_actual + lletra.ancho / 2.0f; + lletra.posicio.y = y_centre; + + // Avançar per a següent lletra + x_actual += lletra.ancho + ESPAI_ENTRE_LLETRES; + } + + std::cout << "[EscenaLogo] " << lletres_.size() + << " lletres carregades, ancho total: " << ancho_total << " px\n"; +} + +float EscenaLogo::calcular_escala_zoom(float temps) const { + if (temps >= DURACIO_ZOOM) { + return ESCALA_FINAL; // Animació acabada + } + + // Progrés normalitzat (0.0 a 1.0) + float t = temps / DURACIO_ZOOM; + + // Ease-out quadràtic: y = 1 - (1-t)^2 + // Comença ràpid, acaba suau + float factor = 1.0f - (1.0f - t) * (1.0f - t); + + // Interpolar entre escala inicial i final + return ESCALA_INICIAL + (ESCALA_FINAL - ESCALA_INICIAL) * factor; +} + void EscenaLogo::actualitzar(float delta_time) { temps_acumulat_ += delta_time; - // Després de 2 segons, saltar al joc - if (temps_acumulat_ >= 2.0f) { + // Després de DURACIO_TOTAL segons, saltar al joc + if (temps_acumulat_ >= DURACIO_TOTAL) { GestorEscenes::actual = GestorEscenes::Escena::JOC; } } void EscenaLogo::dibuixar() { - // Pantalla negra + // Fons negre sdl_.neteja(0, 0, 0); + + // Calcular escala actual del zoom + float escala = calcular_escala_zoom(temps_acumulat_); + + // Dibuixar cada lletra amb l'escala animada + for (const auto& lletra : lletres_) { + Rendering::render_shape( + sdl_.obte_renderer(), + lletra.forma, + lletra.posicio, // Posició en pantalla + 0.0f, // Sense rotació + escala, // Escala animada + true // Dibuixar + ); + } + sdl_.presenta(); } diff --git a/source/game/escenes/escena_logo.hpp b/source/game/escenes/escena_logo.hpp index 8f8a1c9..5a7edf9 100644 --- a/source/game/escenes/escena_logo.hpp +++ b/source/game/escenes/escena_logo.hpp @@ -1,11 +1,15 @@ // escena_logo.hpp - Pantalla d'inici del joc -// Mostra pantalla negra durant 2 segons i salta al joc +// Mostra logo JAILGAMES animat amb zoom i salta al joc // © 2025 Port a C++20 #pragma once #include "../../core/rendering/sdl_manager.hpp" +#include "../../core/graphics/shape.hpp" +#include "../../core/types.hpp" #include +#include +#include class EscenaLogo { public: @@ -16,6 +20,25 @@ private: SDLManager& sdl_; float temps_acumulat_; + // Estructura per a cada lletra del logo + struct LetraLogo { + std::shared_ptr forma; + Punt posicio; // Posició final en pantalla + float ancho; // Ancho per a càlcul de centrat + }; + + std::vector lletres_; // 9 lletres: J-A-I-L-G-A-M-E-S + + // Constants d'animació + static constexpr float DURACIO_ZOOM = 1.5f; // Duració del zoom (segons) + static constexpr float DURACIO_TOTAL = 3.0f; // Duració total abans d'anar al joc + static constexpr float ESCALA_INICIAL = 0.1f; // Escala inicial (10%) + static constexpr float ESCALA_FINAL = 1.0f; // Escala final (100%) + static constexpr float ESPAI_ENTRE_LLETRES = 10.0f; // Espaiat entre lletres + + // Mètodes privats + void inicialitzar_lletres(); + float calcular_escala_zoom(float temps) const; void actualitzar(float delta_time); void dibuixar(); void processar_events(const SDL_Event& event); diff --git a/tools/svg_to_shp.py b/tools/svg_to_shp.py new file mode 100755 index 0000000..7404e7c --- /dev/null +++ b/tools/svg_to_shp.py @@ -0,0 +1,340 @@ +#!/usr/bin/env python3 +""" +svg_to_shp.py - Conversor de jailgames.svg a archivos .shp individuales +Extrae letras del SVG y las convierte al formato .shp del juego Orni Attack + +Uso: python3 svg_to_shp.py +""" + +import sys +import os +import re +import xml.etree.ElementTree as ET + + +def parse_transform_matrix(transform_str): + """ + Parsea string "matrix(a,b,c,d,e,f)" → tupla (a,b,c,d,e,f) + """ + match = re.search(r'matrix\(([\d\.\-,\s]+)\)', transform_str) + if not match: + return (1, 0, 0, 1, 0, 0) # Identidad por defecto + + values = re.split(r'[,\s]+', match.group(1).strip()) + values = [float(v) for v in values if v] + + if len(values) == 6: + return tuple(values) + return (1, 0, 0, 1, 0, 0) + + +def apply_transform(punto, matrix): + """ + Aplica transformación matricial 2D a un punto (x, y) + matrix = (a, b, c, d, e, f) + x' = a*x + c*y + e + y' = b*x + d*y + f + """ + x, y = punto + a, b, c, d, e, f = matrix + x_new = a * x + c * y + e + y_new = b * x + d * y + f + return (x_new, y_new) + + +def parse_svg_path(d_attr): + """ + Convierte comandos SVG path (M y L) a lista de puntos [(x, y), ...] + Ejemplo: "M896,1693L896,1531.23L1219.53,1531.23..." → [(896, 1693), (896, 1531.23), ...] + """ + # Reemplazar comas por espacios para facilitar parsing + d_attr = d_attr.replace(',', ' ') + + # Split por comandos M y L + # Añadir marcador antes de cada comando + d_attr = re.sub(r'([ML])', r'|\1', d_attr) + commands = [c.strip() for c in d_attr.split('|') if c.strip()] + + points = [] + for cmd in commands: + if not cmd: + continue + + # Extraer letra de comando y coordenadas + cmd_letter = cmd[0] + coords_str = cmd[1:].strip() + + if not coords_str: + continue + + # Parsear pares de coordenadas + coords = coords_str.split() + + # Procesar en pares (x, y) + i = 0 + while i < len(coords) - 1: + try: + x = float(coords[i]) + y = float(coords[i + 1]) + points.append((x, y)) + i += 2 + except (ValueError, IndexError): + i += 1 + + return points + + +def rect_to_points(rect_elem): + """ + Convierte elemento a lista de puntos (rectángulo cerrado) + """ + x = float(rect_elem.get('x', 0)) + y = float(rect_elem.get('y', 0)) + width = float(rect_elem.get('width', 0)) + height = float(rect_elem.get('height', 0)) + + # Rectángulo cerrado: 5 puntos (último = primero) + return [ + (x, y), + (x + width, y), + (x + width, y + height), + (x, y + height), + (x, y) # Cerrar + ] + + +def calc_bounding_box(puntos): + """ + Calcula bounding box de una lista de puntos + Retorna: (min_x, max_x, min_y, max_y, ancho, alto) + """ + if not puntos: + return (0, 0, 0, 0, 0, 0) + + xs = [p[0] for p in puntos] + ys = [p[1] for p in puntos] + + min_x = min(xs) + max_x = max(xs) + min_y = min(ys) + max_y = max(ys) + + ancho = max_x - min_x + alto = max_y - min_y + + return (min_x, max_x, min_y, max_y, ancho, alto) + + +def normalizar_letra(nombre, puntos, altura_objetivo=100.0): + """ + Escala y traslada letra para que tenga altura_objetivo pixels + y esté centrada en origen (0, 0) en esquina superior izquierda + + Retorna: dict con puntos normalizados, centro, ancho, alto + """ + if not puntos: + return None + + min_x, max_x, min_y, max_y, ancho, alto = calc_bounding_box(puntos) + + if alto == 0: + print(f" [WARN] Letra {nombre}: altura cero") + return None + + # Factor de escala basado en altura + escala = altura_objetivo / alto + + # Normalizar puntos: + # 1. Trasladar a origen (restar min_x, min_y) + # 2. Aplicar escala + puntos_norm = [] + for x, y in puntos: + x_norm = (x - min_x) * escala + y_norm = (y - min_y) * escala + puntos_norm.append((x_norm, y_norm)) + + # Calcular dimensiones finales + ancho_norm = ancho * escala + alto_norm = alto * escala + + # Centro de la letra + centro = (ancho_norm / 2.0, alto_norm / 2.0) + + return { + 'nombre': nombre, + 'puntos': puntos_norm, + 'centro': centro, + 'ancho': ancho_norm, + 'alto': alto_norm + } + + +def generar_shp(letra_norm, output_dir): + """ + Genera archivo .shp con formato del juego Orni Attack + + Formato: + name: letra_x + scale: 1.0 + center: cx, cy + polyline: x1,y1 x2,y2 x3,y3 ... + """ + if not letra_norm: + return + + nombre_archivo = f"letra_{letra_norm['nombre'].lower()}.shp" + filepath = os.path.join(output_dir, nombre_archivo) + + with open(filepath, 'w', encoding='utf-8') as f: + # Header con comentarios + f.write(f"# {nombre_archivo}\n") + f.write(f"# Generado automáticamente desde jailgames.svg\n") + f.write(f"# Dimensiones: {letra_norm['ancho']:.2f} x {letra_norm['alto']:.2f} px\n") + f.write(f"\n") + + # Metadatos + f.write(f"name: letra_{letra_norm['nombre'].lower()}\n") + f.write(f"scale: 1.0\n") + f.write(f"center: {letra_norm['centro'][0]:.2f}, {letra_norm['centro'][1]:.2f}\n") + f.write(f"\n") + + # Polyline con todos los puntos + f.write("polyline: ") + puntos_str = " ".join([f"{x:.2f},{y:.2f}" for x, y in letra_norm['puntos']]) + f.write(puntos_str) + f.write("\n") + + print(f" ✓ {nombre_archivo:20} ({len(letra_norm['puntos']):3} puntos, " + f"{letra_norm['ancho']:6.2f} x {letra_norm['alto']:6.2f} px)") + + +def parse_svg(filepath): + """ + Parsea jailgames.svg y extrae las 9 letras con sus puntos transformados + + Retorna: lista de dicts con {nombre, puntos} + """ + tree = ET.parse(filepath) + root = tree.getroot() + + # Namespace SVG + ns = {'svg': 'http://www.w3.org/2000/svg'} + + # Buscar grupo con transform + groups = root.findall('.//svg:g[@transform]', ns) + if not groups: + print("[ERROR] No se encontró grupo con transform") + return [] + + group = groups[0] + transform_str = group.get('transform', '') + transform_matrix = parse_transform_matrix(transform_str) + + print(f"[INFO] Transform matrix: {transform_matrix}") + + # Extraer paths y rects + paths = group.findall('svg:path', ns) + rects = group.findall('svg:rect', ns) + + print(f"[INFO] Encontrados {len(paths)} paths y {len(rects)} rects") + + # Nombres de las letras para paths (sin I que es un rect) + nombres_paths = ['J', 'A', 'L', 'G', 'A', 'M', 'E', 'S'] + + letras = [] + + # Procesar paths + for i, path in enumerate(paths): + if i >= len(nombres_paths): + break + + d_attr = path.get('d') + if not d_attr: + continue + + # Parsear puntos del path + puntos = parse_svg_path(d_attr) + + # Aplicar transformación + puntos = [apply_transform(p, transform_matrix) for p in puntos] + + letras.append({ + 'nombre': nombres_paths[i], + 'puntos': puntos + }) + + # Procesar rects (la letra I es un rect) + for rect in rects: + puntos = rect_to_points(rect) + + # Aplicar transformación + puntos = [apply_transform(p, transform_matrix) for p in puntos] + + letras.append({ + 'nombre': 'I', + 'puntos': puntos + }) + + return letras + + +def main(): + if len(sys.argv) != 3: + print("Uso: python3 svg_to_shp.py ") + print("Ejemplo: python3 svg_to_shp.py jailgames.svg data/shapes/") + sys.exit(1) + + svg_path = sys.argv[1] + output_dir = sys.argv[2] + + # Verificar que el SVG existe + if not os.path.exists(svg_path): + print(f"[ERROR] No se encuentra el archivo: {svg_path}") + sys.exit(1) + + # Crear directorio de salida si no existe + os.makedirs(output_dir, exist_ok=True) + + print(f"\n{'='*70}") + print(f" SVG → .shp Converter para Orni Attack") + print(f"{'='*70}\n") + print(f"Input: {svg_path}") + print(f"Output: {output_dir}/\n") + + # Parsear SVG + print("[1/3] Parseando SVG...") + letras = parse_svg(svg_path) + + if not letras: + print("[ERROR] No se pudieron extraer letras del SVG") + sys.exit(1) + + print(f" ✓ Extraídas {len(letras)} letras\n") + + # Filtrar duplicados (solo una 'A') + print("[2/3] Filtrando duplicados...") + letras_unicas = {} + for letra in letras: + nombre = letra['nombre'] + if nombre not in letras_unicas: + letras_unicas[nombre] = letra + + print(f" ✓ {len(letras_unicas)} letras únicas: {', '.join(sorted(letras_unicas.keys()))}\n") + + # Normalizar y generar .shp + print("[3/3] Generando archivos .shp (altura objetivo: 100px)...\n") + + for nombre in sorted(letras_unicas.keys()): + letra = letras_unicas[nombre] + letra_norm = normalizar_letra(nombre, letra['puntos'], altura_objetivo=100.0) + + if letra_norm: + generar_shp(letra_norm, output_dir) + + print(f"\n{'='*70}") + print(f" ✓ Conversión completada: {len(letras_unicas)} archivos .shp generados") + print(f"{'='*70}\n") + + +if __name__ == '__main__': + main()