diff --git a/CMakeLists.txt b/CMakeLists.txt index 34dc905..a8e9125 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,8 @@ set(APP_SOURCES source/core/graphics/shape_loader.cpp source/core/graphics/vector_text.cpp source/game/options.cpp - source/game/joc_asteroides.cpp + source/game/escenes/escena_logo.cpp + source/game/escenes/escena_joc.cpp source/game/entities/nau.cpp source/game/entities/bala.cpp source/game/entities/enemic.cpp diff --git a/Makefile b/Makefile index e530c16..bd4f719 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,8 @@ APP_SOURCES := \ source/core/graphics/shape_loader.cpp \ source/core/graphics/vector_text.cpp \ source/game/options.cpp \ - source/game/joc_asteroides.cpp \ + source/game/escenes/escena_logo.cpp \ + source/game/escenes/escena_joc.cpp \ source/game/entities/nau.cpp \ source/game/entities/bala.cpp \ source/game/entities/enemic.cpp diff --git a/source/game/escenes/escena_joc.cpp b/source/game/escenes/escena_joc.cpp new file mode 100644 index 0000000..41122ab --- /dev/null +++ b/source/game/escenes/escena_joc.cpp @@ -0,0 +1,186 @@ +// escena_joc.cpp - Implementació de la lògica del joc +// © 1999 Visente i Sergi (versió Pascal) +// © 2025 Port a C++20 amb SDL3 + +#include "escena_joc.hpp" +#include "../../core/system/gestor_escenes.hpp" +#include +#include +#include +#include + +EscenaJoc::EscenaJoc(SDLManager& sdl) + : sdl_(sdl), nau_(sdl.obte_renderer()), itocado_(0), text_(sdl.obte_renderer()) { + // Inicialitzar bales amb renderer + for (auto &bala : bales_) { + bala = Bala(sdl.obte_renderer()); + } + + // Inicialitzar enemics amb renderer + for (auto &enemy : orni_) { + enemy = Enemic(sdl.obte_renderer()); + } +} + +void EscenaJoc::executar() { + std::cout << "Escena Joc: Inicialitzant...\n"; + + // Inicialitzar estat del joc + inicialitzar(); + + SDL_Event event; + Uint64 last_time = SDL_GetTicks(); + + while (GestorEscenes::actual == GestorEscenes::Escena::JOC) { + // Calcular delta_time real + Uint64 current_time = SDL_GetTicks(); + float delta_time = (current_time - last_time) / 1000.0f; + last_time = current_time; + + // Limitar delta_time per evitar grans salts + if (delta_time > 0.05f) { + delta_time = 0.05f; + } + + // Processar events SDL + while (SDL_PollEvent(&event)) { + // Manejo de finestra + if (sdl_.handleWindowEvent(event)) { + 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; + } + } + + // Processament normal del joc + 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 + actualitzar(delta_time); + + // Actualitzar colors oscil·lats + sdl_.updateColors(delta_time); + + // Netejar pantalla (usa color oscil·lat) + sdl_.neteja(0, 0, 0); + + // Dibuixar joc + dibuixar(); + + // Presentar renderer (swap buffers) + sdl_.presenta(); + } + + std::cout << "Escena Joc: Finalitzant...\n"; +} + +void EscenaJoc::inicialitzar() { + // Inicialitzar generador de números aleatoris + // Basat en el codi Pascal original: line 376 + std::srand(static_cast(std::time(nullptr))); + + // Inicialitzar estat de col·lisió + itocado_ = 0; + + // Inicialitzar nau + nau_.inicialitzar(); + + // Inicialitzar enemics (ORNIs) + for (auto &enemy : orni_) { + enemy.inicialitzar(); + } + + // Inicialitzar bales + for (auto &bala : bales_) { + bala.inicialitzar(); + } +} + +void EscenaJoc::actualitzar(float delta_time) { + // Actualitzar nau (input + física) + nau_.processar_input(delta_time); + nau_.actualitzar(delta_time); + + // Actualitzar moviment i rotació dels enemics (ORNIs) + for (auto &enemy : orni_) { + enemy.actualitzar(delta_time); + } + + // Actualitzar moviment de bales (Fase 9) + for (auto &bala : bales_) { + bala.actualitzar(delta_time); + } +} + +void EscenaJoc::dibuixar() { + // Dibuixar nau + nau_.dibuixar(); + + // Dibuixar ORNIs (enemics) + for (const auto &enemy : orni_) { + enemy.dibuixar(); + } + + // Dibuixar bales (Fase 9) + for (const auto &bala : bales_) { + bala.dibuixar(); + } + + // [PRUEBA] Text vectorial + text_.render("0123456789", {10, 10}, 1.5f); + text_.render("SCORE: 1234", {10, 40}, 1.0f); + text_.render("10:45", {10, 70}, 2.0f); + text_.render("LEVEL-3", {10, 110}, 1.5f); + + // TODO: Dibuixar marges (Fase 11) +} + +void EscenaJoc::processar_input(const SDL_Event &event) { + // Processament d'input per events puntuals (no continus) + // L'input continu (fletxes) es processa en actualitzar() amb + // SDL_GetKeyboardState() + + if (event.type == SDL_EVENT_KEY_DOWN) { + switch (event.key.key) { + case SDLK_SPACE: + // Disparar (Fase 9) + // Basat en el codi Pascal original: crear bala en posició de la nau + // El joc original només permetia 1 bala activa alhora + + // Buscar primera bala inactiva + for (auto &bala : bales_) { + if (!bala.esta_activa()) { + bala.disparar(nau_.get_centre(), nau_.get_angle()); + break; + } + } + break; + + default: + break; + } + } +} + +void EscenaJoc::tocado() { + // TODO: Implementar seqüència de mort +} diff --git a/source/game/escenes/escena_joc.hpp b/source/game/escenes/escena_joc.hpp new file mode 100644 index 0000000..fc64690 --- /dev/null +++ b/source/game/escenes/escena_joc.hpp @@ -0,0 +1,48 @@ +// escena_joc.hpp - Lògica principal del joc +// © 1999 Visente i Sergi (versió Pascal) +// © 2025 Port a C++20 amb SDL3 + +#ifndef ESCENA_JOC_HPP +#define ESCENA_JOC_HPP + +#include "../../core/graphics/vector_text.hpp" +#include "../../core/rendering/sdl_manager.hpp" +#include "../../core/types.hpp" +#include "../constants.hpp" +#include "../entities/bala.hpp" +#include "../entities/enemic.hpp" +#include "../entities/nau.hpp" +#include +#include +#include + +// Classe principal del joc (escena) +class EscenaJoc { +public: + explicit EscenaJoc(SDLManager& sdl); + ~EscenaJoc() = default; + + void executar(); // Bucle principal de l'escena + void inicialitzar(); + void actualitzar(float delta_time); + void dibuixar(); + void processar_input(const SDL_Event &event); + +private: + SDLManager& sdl_; + + // Estat del joc + Nau nau_; + std::array orni_; + std::array bales_; + Poligon chatarra_cosmica_; + uint16_t itocado_; + + // Text vectorial + Graphics::VectorText text_; + + // Funcions privades + void tocado(); +}; + +#endif // ESCENA_JOC_HPP diff --git a/source/game/escenes/escena_logo.cpp b/source/game/escenes/escena_logo.cpp new file mode 100644 index 0000000..1757791 --- /dev/null +++ b/source/game/escenes/escena_logo.cpp @@ -0,0 +1,91 @@ +// escena_logo.cpp - Implementació de l'escena logo +// © 2025 Port a C++20 + +#include "escena_logo.hpp" +#include "../../core/system/gestor_escenes.hpp" +#include + +EscenaLogo::EscenaLogo(SDLManager& sdl) + : sdl_(sdl), temps_acumulat_(0.0f) { + std::cout << "Escena Logo: Inicialitzant...\n"; +} + +void EscenaLogo::executar() { + SDL_Event event; + Uint64 last_time = SDL_GetTicks(); + + while (GestorEscenes::actual == GestorEscenes::Escena::LOGO) { + // Calcular delta_time real + Uint64 current_time = SDL_GetTicks(); + float delta_time = (current_time - last_time) / 1000.0f; + last_time = current_time; + + // Limitar delta_time per evitar grans salts + if (delta_time > 0.05f) { + delta_time = 0.05f; + } + + // Processar events SDL + while (SDL_PollEvent(&event)) { + // Manejo de finestra + if (sdl_.handleWindowEvent(event)) { + 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; + } + } + + // Processar events de l'escena + 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); + + // Dibuixar + dibuixar(); + } + + std::cout << "Escena Logo: Finalitzant...\n"; +} + +void EscenaLogo::actualitzar(float delta_time) { + temps_acumulat_ += delta_time; + + // Després de 2 segons, saltar al joc + if (temps_acumulat_ >= 2.0f) { + GestorEscenes::actual = GestorEscenes::Escena::JOC; + } +} + +void EscenaLogo::dibuixar() { + // Pantalla negra + sdl_.neteja(0, 0, 0); + sdl_.presenta(); +} + +void EscenaLogo::processar_events(const SDL_Event& event) { + // Qualsevol tecla o clic de ratolí salta al joc + if (event.type == SDL_EVENT_KEY_DOWN || + event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) { + GestorEscenes::actual = GestorEscenes::Escena::JOC; + } +} diff --git a/source/game/escenes/escena_logo.hpp b/source/game/escenes/escena_logo.hpp new file mode 100644 index 0000000..8f8a1c9 --- /dev/null +++ b/source/game/escenes/escena_logo.hpp @@ -0,0 +1,22 @@ +// escena_logo.hpp - Pantalla d'inici del joc +// Mostra pantalla negra durant 2 segons i salta al joc +// © 2025 Port a C++20 + +#pragma once + +#include "../../core/rendering/sdl_manager.hpp" +#include + +class EscenaLogo { +public: + explicit EscenaLogo(SDLManager& sdl); + void executar(); // Bucle principal de l'escena + +private: + SDLManager& sdl_; + float temps_acumulat_; + + void actualitzar(float delta_time); + void dibuixar(); + void processar_events(const SDL_Event& event); +}; diff --git a/source/game/joc_asteroides.cpp b/source/game/joc_asteroides.cpp deleted file mode 100644 index e2f022d..0000000 --- a/source/game/joc_asteroides.cpp +++ /dev/null @@ -1,114 +0,0 @@ -// joc_asteroides.cpp - Implementació de la lògica del joc -// © 1999 Visente i Sergi (versió Pascal) -// © 2025 Port a C++20 amb SDL3 - -#include "joc_asteroides.hpp" -#include -#include -#include -#include - -JocAsteroides::JocAsteroides(SDL_Renderer *renderer) - : renderer_(renderer), nau_(renderer), itocado_(0), text_(renderer) { - // Inicialitzar bales amb renderer - for (auto &bala : bales_) { - bala = Bala(renderer); - } - - // Inicialitzar enemics amb renderer - for (auto &enemy : orni_) { - enemy = Enemic(renderer); - } -} - -void JocAsteroides::inicialitzar() { - // Inicialitzar generador de números aleatoris - // Basat en el codi Pascal original: line 376 - std::srand(static_cast(std::time(nullptr))); - - // Inicialitzar estat de col·lisió - itocado_ = 0; - - // Inicialitzar nau - nau_.inicialitzar(); - - // Inicialitzar enemics (ORNIs) - for (auto &enemy : orni_) { - enemy.inicialitzar(); - } - - // Inicialitzar bales - for (auto &bala : bales_) { - bala.inicialitzar(); - } -} - -void JocAsteroides::actualitzar(float delta_time) { - // Actualitzar nau (input + física) - nau_.processar_input(delta_time); - nau_.actualitzar(delta_time); - - // Actualitzar moviment i rotació dels enemics (ORNIs) - for (auto &enemy : orni_) { - enemy.actualitzar(delta_time); - } - - // Actualitzar moviment de bales (Fase 9) - for (auto &bala : bales_) { - bala.actualitzar(delta_time); - } -} - -void JocAsteroides::dibuixar() { - // Dibuixar nau - nau_.dibuixar(); - - // Dibuixar ORNIs (enemics) - for (const auto &enemy : orni_) { - enemy.dibuixar(); - } - - // Dibuixar bales (Fase 9) - for (const auto &bala : bales_) { - bala.dibuixar(); - } - - // [PRUEBA] Text vectorial - text_.render("0123456789", {10, 10}, 1.5f); - text_.render("SCORE: 1234", {10, 40}, 1.0f); - text_.render("10:45", {10, 70}, 2.0f); - text_.render("LEVEL-3", {10, 110}, 1.5f); - - // TODO: Dibuixar marges (Fase 11) -} - -void JocAsteroides::processar_input(const SDL_Event &event) { - // Processament d'input per events puntuals (no continus) - // L'input continu (fletxes) es processa en actualitzar() amb - // SDL_GetKeyboardState() - - if (event.type == SDL_EVENT_KEY_DOWN) { - switch (event.key.key) { - case SDLK_SPACE: - // Disparar (Fase 9) - // Basat en el codi Pascal original: crear bala en posició de la nau - // El joc original només permetia 1 bala activa alhora - - // Buscar primera bala inactiva - for (auto &bala : bales_) { - if (!bala.esta_activa()) { - bala.disparar(nau_.get_centre(), nau_.get_angle()); - break; - } - } - break; - - default: - break; - } - } -} - -void JocAsteroides::tocado() { - // TODO: Implementar seqüència de mort -} diff --git a/source/game/joc_asteroides.hpp b/source/game/joc_asteroides.hpp deleted file mode 100644 index 7a89b48..0000000 --- a/source/game/joc_asteroides.hpp +++ /dev/null @@ -1,46 +0,0 @@ -// joc_asteroides.hpp - Lògica principal del joc -// © 1999 Visente i Sergi (versió Pascal) -// © 2025 Port a C++20 amb SDL3 - -#ifndef JOC_ASTEROIDES_HPP -#define JOC_ASTEROIDES_HPP - -#include "core/graphics/vector_text.hpp" -#include "core/types.hpp" -#include "game/constants.hpp" -#include "game/entities/bala.hpp" -#include "game/entities/enemic.hpp" -#include "game/entities/nau.hpp" -#include -#include -#include - -// Classe principal del joc -class JocAsteroides { -public: - JocAsteroides(SDL_Renderer *renderer); - ~JocAsteroides() = default; - - void inicialitzar(); - void actualitzar(float delta_time); - void dibuixar(); - void processar_input(const SDL_Event &event); - -private: - SDL_Renderer *renderer_; - - // Estat del joc - Nau nau_; - std::array orni_; - std::array bales_; - Poligon chatarra_cosmica_; - uint16_t itocado_; - - // [NUEVO] Text vectorial - Graphics::VectorText text_; - - // Funcions privades - void tocado(); -}; - -#endif // JOC_ASTEROIDES_HPP