diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cc2490..b20f1d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,9 +36,14 @@ set(APP_SOURCES source/main.cpp source/core/system/director.cpp source/core/rendering/sdl_manager.cpp + source/core/rendering/line_renderer.cpp + source/core/rendering/polygon_renderer.cpp + source/core/rendering/primitives.cpp source/game/options.cpp source/game/joc_asteroides.cpp - source/core/rendering/primitives.cpp + source/game/entities/nau.cpp + source/game/entities/bala.cpp + source/game/entities/enemic.cpp ) # Configuración de SDL3 diff --git a/Makefile b/Makefile index b0bfb2f..4298a91 100644 --- a/Makefile +++ b/Makefile @@ -34,9 +34,16 @@ endif # ============================================================================== APP_SOURCES := \ source/main.cpp \ + source/core/system/director.cpp \ source/core/rendering/sdl_manager.cpp \ + source/core/rendering/line_renderer.cpp \ + source/core/rendering/polygon_renderer.cpp \ + source/core/rendering/primitives.cpp \ + source/game/options.cpp \ source/game/joc_asteroides.cpp \ - source/core/rendering/primitives.cpp + source/game/entities/nau.cpp \ + source/game/entities/bala.cpp \ + source/game/entities/enemic.cpp # ============================================================================== # INCLUDES @@ -87,7 +94,7 @@ endif # ============================================================================== # TARGETS # ============================================================================== -.PHONY: all clean debug help +.PHONY: all clean debug help backup # Default target all: $(TARGET_FILE) @@ -130,16 +137,30 @@ else endif @echo Clean complete +# Backup to remote server +backup: + @echo "Backing up project to maverick:/home/sergio/git-backup/asteroids..." + rsync -a --delete \ + --exclude='build/' \ + --exclude='*.o' \ + --exclude='*.exe' \ + --exclude='orni' \ + --exclude='orni_debug' \ + --exclude='*_release/' \ + $(DIR_ROOT) maverick:/home/sergio/git-backup/asteroids/ + @echo "Backup completed successfully" + # Help target help: - @echo Available targets: - @echo all - Build the game (default) - @echo debug - Build with debug symbols - @echo clean - Remove build artifacts - @echo help - Show this help message - @echo. - @echo Current configuration: - @echo Target: $(TARGET_NAME) - @echo Version: $(VERSION) - @echo Platform: $(UNAME_S) - @echo C++ Standard: $(CPP_STANDARD) + @echo "Available targets:" + @echo " all - Build the game (default)" + @echo " debug - Build with debug symbols" + @echo " clean - Remove build artifacts" + @echo " backup - Backup project to remote server" + @echo " help - Show this help message" + @echo "" + @echo "Current configuration:" + @echo " Target: $(TARGET_NAME)" + @echo " Version: $(VERSION)" + @echo " Platform: $(UNAME_S)" + @echo " C++ Standard: $(CPP_STANDARD)" diff --git a/source/game/entities/bala.cpp b/source/game/entities/bala.cpp new file mode 100644 index 0000000..290faad --- /dev/null +++ b/source/game/entities/bala.cpp @@ -0,0 +1,83 @@ +// bala.cpp - Implementació de projectils de la nau +// © 1999 Visente i Sergi (versió Pascal) +// © 2025 Port a C++20 amb SDL3 + +#include "game/entities/bala.hpp" +#include "core/rendering/polygon_renderer.hpp" +#include "core/rendering/primitives.hpp" +#include "game/constants.hpp" +#include + +Bala::Bala(SDL_Renderer *renderer) : renderer_(renderer) {} + +void Bala::inicialitzar() { + // Inicialitzar bala com a pentàgon petit + // Basat en el codi Pascal original: inicialment inactiva + // Copiat de joc_asteroides.cpp línies 58-64 + + // Crear pentàgon petit (5 costats, radi 5) + crear_poligon_regular(dades_, 5, 5.0f); + + // Inicialment inactiva + dades_.esta = false; +} + +void Bala::disparar(const Punt &posicio, float angle) { + // Activar bala i posicionar-la a la nau + // Basat en joc_asteroides.cpp línies 188-200 + + // Activar bala + dades_.esta = true; + + // Posició inicial = centre de la nau + dades_.centre.x = posicio.x; + dades_.centre.y = posicio.y; + + // Angle = angle de la nau (dispara en la direcció que apunta) + dades_.angle = angle; + + // Velocitat alta (el joc Pascal original usava 7 px/frame) + // 7 px/frame × 20 FPS = 140 px/s + dades_.velocitat = 140.0f; +} + +void Bala::actualitzar(float delta_time) { + if (dades_.esta) { + mou(delta_time); + } +} + +void Bala::dibuixar() const { + if (dades_.esta) { + // Dibuixar com a pentàgon petit, sense rotació visual + Rendering::rota_pol(renderer_, dades_, 0.0f, true); + } +} + +void Bala::mou(float delta_time) { + // Moviment rectilini de la bala + // 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) + // velocitat ja està en px/s (140 px/s), només cal multiplicar per delta_time + float velocitat_efectiva = dades_.velocitat * delta_time; + + // Calcular desplaçament (angle-PI/2 perquè angle=0 apunta amunt) + float dy = + velocitat_efectiva * std::sin(dades_.angle - Constants::PI / 2.0f); + float dx = + velocitat_efectiva * std::cos(dades_.angle - Constants::PI / 2.0f); + + // Acumulació directa amb precisió subpíxel + dades_.centre.y += dy; + dades_.centre.x += dx; + + // Desactivar si surt dels marges (no rebota com els ORNIs) + if (dades_.centre.x < Constants::MARGE_ESQ || + dades_.centre.x > Constants::MARGE_DRET || + dades_.centre.y < Constants::MARGE_DALT || + dades_.centre.y > Constants::MARGE_BAIX) { + dades_.esta = false; + } +} diff --git a/source/game/entities/bala.hpp b/source/game/entities/bala.hpp new file mode 100644 index 0000000..9be39c6 --- /dev/null +++ b/source/game/entities/bala.hpp @@ -0,0 +1,28 @@ +// bala.hpp - Classe per a projectils de la nau +// © 1999 Visente i Sergi (versió Pascal) +// © 2025 Port a C++20 amb SDL3 + +#pragma once +#include "core/types.hpp" +#include + +class Bala { +public: + Bala() : renderer_(nullptr) {} + Bala(SDL_Renderer *renderer); + + void inicialitzar(); + void disparar(const Punt &posicio, float angle); + void actualitzar(float delta_time); + void dibuixar() const; + + // Getters + bool esta_activa() const { return dades_.esta; } + const Punt &get_centre() const { return dades_.centre; } + void desactivar() { dades_.esta = false; } + +private: + SDL_Renderer *renderer_; + Poligon dades_; + void mou(float delta_time); +}; diff --git a/source/game/entities/enemic.cpp b/source/game/entities/enemic.cpp new file mode 100644 index 0000000..786c7c9 --- /dev/null +++ b/source/game/entities/enemic.cpp @@ -0,0 +1,97 @@ +// enemic.cpp - Implementació d'enemics (ORNIs) +// © 1999 Visente i Sergi (versió Pascal) +// © 2025 Port a C++20 amb SDL3 + +#include "game/entities/enemic.hpp" +#include "core/rendering/polygon_renderer.hpp" +#include "core/rendering/primitives.hpp" +#include "game/constants.hpp" +#include +#include + +Enemic::Enemic(SDL_Renderer *renderer) : renderer_(renderer) {} + +void Enemic::inicialitzar() { + // Inicialitzar enemic com a pentàgon + // Copiat de joc_asteroides.cpp línies 41-54 + + // Crear pentàgon regular (5 costats, radi 20) + crear_poligon_regular(dades_, 5, 20.0f); + + // Posició aleatòria dins de l'àrea de joc + dades_.centre.x = static_cast((std::rand() % 580) + 30); // 30-610 + dades_.centre.y = static_cast((std::rand() % 420) + 30); // 30-450 + + // Angle aleatori + dades_.angle = (std::rand() % 360) * Constants::PI / 180.0f; + + // Està actiu + dades_.esta = true; +} + +void Enemic::actualitzar(float delta_time) { + if (dades_.esta) { + // Moviment autònom + mou(delta_time); + + // Rotació visual (time-based: drotacio està en rad/s) + dades_.rotacio += dades_.drotacio * delta_time; + } +} + +void Enemic::dibuixar() const { + if (dades_.esta) { + Rendering::rota_pol(renderer_, dades_, dades_.rotacio, true); + } +} + +void Enemic::mou(float delta_time) { + // Moviment autònom d'ORNI (enemic pentàgon) + // Basat EXACTAMENT en el codi Pascal original: ASTEROID.PAS lines 279-293 + // Copiat EXACTAMENT de joc_asteroides.cpp línies 348-394 + // + // IMPORTANT: El Pascal original NO té canvi aleatori continu! + // Només ajusta l'angle quan toca una paret. + + // Calcular nova posició PROPUESTA (time-based, però lògica Pascal) + // velocitat ja està en px/s (40 px/s), multiplicar per delta_time + float velocitat_efectiva = dades_.velocitat * delta_time; + + // Calcular desplaçament (angle-PI/2 perquè angle=0 apunta amunt) + float dy = + velocitat_efectiva * std::sin(dades_.angle - Constants::PI / 2.0f); + float dx = + velocitat_efectiva * std::cos(dades_.angle - Constants::PI / 2.0f); + + float new_y = dades_.centre.y + dy; + float new_x = dades_.centre.x + dx; + + // Lògica Pascal: Actualitza Y si dins, sinó ajusta angle aleatòriament + // if (dy>marge_dalt) and (dy Constants::MARGE_DALT && new_y < Constants::MARGE_BAIX) { + dades_.centre.y = new_y; + } else { + // Pequeño ajuste aleatorio: (random(256)/512)*(random(3)-1) + // random(256) = 0..255, /512 = 0..0.498 + // random(3) = 0,1,2, -1 = -1,0,1 + // Resultado: ±0.5 rad aprox + float rand1 = (static_cast(std::rand() % 256) / 512.0f); + int rand2 = (std::rand() % 3) - 1; // -1, 0, o 1 + dades_.angle += rand1 * static_cast(rand2); + } + + // Lògica Pascal: Actualitza X si dins, sinó ajusta angle aleatòriament + // if (dx>marge_esq) and (dx Constants::MARGE_ESQ && new_x < Constants::MARGE_DRET) { + dades_.centre.x = new_x; + } else { + float rand1 = (static_cast(std::rand() % 256) / 512.0f); + int rand2 = (std::rand() % 3) - 1; + dades_.angle += rand1 * static_cast(rand2); + } + + // Nota: La rotació visual (dades_.rotacio += dades_.drotacio) ja es fa a + // actualitzar() +} diff --git a/source/game/entities/enemic.hpp b/source/game/entities/enemic.hpp new file mode 100644 index 0000000..c743b39 --- /dev/null +++ b/source/game/entities/enemic.hpp @@ -0,0 +1,27 @@ +// enemic.hpp - Classe per a enemics (ORNIs pentàgons) +// © 1999 Visente i Sergi (versió Pascal) +// © 2025 Port a C++20 amb SDL3 + +#pragma once +#include "core/types.hpp" +#include + +class Enemic { +public: + Enemic() : renderer_(nullptr) {} + Enemic(SDL_Renderer *renderer); + + void inicialitzar(); + void actualitzar(float delta_time); + void dibuixar() const; + + // Getters + bool esta_actiu() const { return dades_.esta; } + const Punt &get_centre() const { return dades_.centre; } + void destruir() { dades_.esta = false; } + +private: + SDL_Renderer *renderer_; + Poligon dades_; + void mou(float delta_time); +}; diff --git a/source/game/entities/nau.cpp b/source/game/entities/nau.cpp new file mode 100644 index 0000000..1734bb9 --- /dev/null +++ b/source/game/entities/nau.cpp @@ -0,0 +1,124 @@ +// nau.cpp - Implementació de la nave del jugador +// © 1999 Visente i Sergi (versió Pascal) +// © 2025 Port a C++20 amb SDL3 + +#include "game/entities/nau.hpp" +#include "core/defaults.hpp" +#include "core/rendering/polygon_renderer.hpp" +#include "game/constants.hpp" +#include +#include + +Nau::Nau(SDL_Renderer *renderer) + : renderer_(renderer), esta_tocada_(false) {} + +void Nau::inicialitzar() { + // Inicialització de la nau (triangle) + // Basat en el codi Pascal original: lines 380-384 + // Copiat de joc_asteroides.cpp línies 30-44 + + // Configurar triangle amb 3 punts polars + dades_.p1.r = 12.0f; + dades_.p1.angle = 3.0f * Constants::PI / 2.0f; // Apunta amunt (270°) + + dades_.p2.r = 12.0f; + dades_.p2.angle = Constants::PI / 4.0f; // 45° + + dades_.p3.r = 12.0f; + dades_.p3.angle = (3.0f * Constants::PI) / 4.0f; // 135° + + // Posició inicial al centre de la pantalla + dades_.centre.x = 320.0f; + dades_.centre.y = 240.0f; + + // Estat inicial + dades_.angle = 0.0f; + dades_.velocitat = 0.0f; + esta_tocada_ = false; +} + +void Nau::processar_input(float delta_time) { + // Processar input continu (com teclapuls() del Pascal original) + // Basat en joc_asteroides.cpp línies 66-85 + // Només processa input si la nau està viva + if (esta_tocada_) + return; + + // Obtenir estat actual del teclat (no events, sinó estat continu) + const bool *keyboard_state = SDL_GetKeyboardState(nullptr); + + // Rotació + if (keyboard_state[SDL_SCANCODE_RIGHT]) { + dades_.angle += Defaults::Physics::ROTATION_SPEED * delta_time; + } + + if (keyboard_state[SDL_SCANCODE_LEFT]) { + dades_.angle -= Defaults::Physics::ROTATION_SPEED * delta_time; + } + + // Acceleració + if (keyboard_state[SDL_SCANCODE_UP]) { + if (dades_.velocitat < Defaults::Physics::MAX_VELOCITY) { + dades_.velocitat += Defaults::Physics::ACCELERATION * delta_time; + if (dades_.velocitat > Defaults::Physics::MAX_VELOCITY) { + dades_.velocitat = Defaults::Physics::MAX_VELOCITY; + } + } + } +} + +void Nau::actualitzar(float delta_time) { + // Només actualitzar si la nau està viva + if (esta_tocada_) + return; + + // Aplicar física (moviment + fricció) + aplicar_fisica(delta_time); +} + +void Nau::dibuixar() const { + // Només dibuixar si la nau està viva + if (esta_tocada_) + return; + + // Escalar velocitat per l'efecte visual (200 px/s → ~6 px d'efecte) + // El codi Pascal original sumava velocitat (0-6) al radi per donar + // sensació de "empenta". Ara velocitat està en px/s (0-200). + // Basat en joc_asteroides.cpp línies 127-134 + float velocitat_visual = dades_.velocitat / 33.33f; + + Rendering::rota_tri(renderer_, dades_, dades_.angle, velocitat_visual, true); +} + +void Nau::aplicar_fisica(float delta_time) { + // Aplicar física de moviment + // Basat en joc_asteroides.cpp línies 87-113 + + // Calcular nova posició basada en velocitat i angle + // S'usa (angle - PI/2) perquè angle=0 apunta cap amunt, no cap a la dreta + // velocitat està en px/s, així que multipliquem per delta_time + float dy = (dades_.velocitat * delta_time) * + std::sin(dades_.angle - Constants::PI / 2.0f) + + dades_.centre.y; + float dx = (dades_.velocitat * delta_time) * + std::cos(dades_.angle - Constants::PI / 2.0f) + + dades_.centre.x; + + // Boundary checking - només actualitzar si dins dels marges + // Acumulació directa amb precisió subpíxel + if (dy > Constants::MARGE_DALT && dy < Constants::MARGE_BAIX) { + dades_.centre.y = dy; + } + + if (dx > Constants::MARGE_ESQ && dx < Constants::MARGE_DRET) { + dades_.centre.x = dx; + } + + // Fricció - desacceleració gradual (time-based) + if (dades_.velocitat > 0.1f) { + dades_.velocitat -= Defaults::Physics::FRICTION * delta_time; + if (dades_.velocitat < 0.0f) { + dades_.velocitat = 0.0f; + } + } +} diff --git a/source/game/entities/nau.hpp b/source/game/entities/nau.hpp new file mode 100644 index 0000000..b12672d --- /dev/null +++ b/source/game/entities/nau.hpp @@ -0,0 +1,33 @@ +// nau.hpp - Classe per a la nave del jugador +// © 1999 Visente i Sergi (versió Pascal) +// © 2025 Port a C++20 amb SDL3 + +#pragma once +#include "core/types.hpp" +#include + +class Nau { +public: + Nau() : renderer_(nullptr) {} + Nau(SDL_Renderer *renderer); + + void inicialitzar(); + void processar_input(float delta_time); + void actualitzar(float delta_time); + void dibuixar() const; + + // Getters + const Punt &get_centre() const { return dades_.centre; } + float get_angle() const { return dades_.angle; } + bool esta_viva() const { return !esta_tocada_; } + + // Col·lisions (Fase 10) + void marcar_tocada() { esta_tocada_ = true; } + +private: + SDL_Renderer *renderer_; + Triangle dades_; + bool esta_tocada_; + + void aplicar_fisica(float delta_time); +}; diff --git a/source/game/joc_asteroides.cpp b/source/game/joc_asteroides.cpp index d6e6982..f5f678d 100644 --- a/source/game/joc_asteroides.cpp +++ b/source/game/joc_asteroides.cpp @@ -10,160 +10,68 @@ #include JocAsteroides::JocAsteroides(SDL_Renderer *renderer) - : renderer_(renderer), itocado_(0) {} + : renderer_(renderer), nau_(renderer), itocado_(0) { + // 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))); - // Inicialització de la nau (triangle) - // Basat en el codi Pascal original: lines 380-384 - nau_.p1.r = 12.0f; - nau_.p1.angle = 3.0f * Constants::PI / 2.0f; // Apunta amunt (270°) - - nau_.p2.r = 12.0f; - nau_.p2.angle = Constants::PI / 4.0f; // 45° - - nau_.p3.r = 12.0f; - nau_.p3.angle = (3.0f * Constants::PI) / 4.0f; // 135° - - nau_.angle = 0.0f; - nau_.centre.x = 320.0f; - nau_.centre.y = 240.0f; - nau_.velocitat = 0.0f; - // Inicialitzar estat de col·lisió itocado_ = 0; + // Inicialitzar nau + nau_.inicialitzar(); + // Inicialitzar enemics (ORNIs) - // Basat en el codi Pascal original: line 386 - for (int i = 0; i < Constants::MAX_ORNIS; i++) { - // Crear pentàgon regular (5 costats, radi 20) - crear_poligon_regular(orni_[i], 5, 20.0f); - - // Posició aleatòria dins de l'àrea de joc - orni_[i].centre.x = static_cast((std::rand() % 580) + 30); // 30-610 - orni_[i].centre.y = static_cast((std::rand() % 420) + 30); // 30-450 - - // Angle aleatori - orni_[i].angle = (std::rand() % 360) * Constants::PI / 180.0f; - - // Està actiu - orni_[i].esta = true; + for (auto &enemy : orni_) { + enemy.inicialitzar(); } // Inicialitzar bales - // Basat en el codi Pascal original: inicialment inactives - for (int i = 0; i < Constants::MAX_BALES; i++) { - // Crear pentàgon petit (5 costats, radi 5) - crear_poligon_regular(bales_[i], 5, 5.0f); - - // Inicialment inactiva - bales_[i].esta = false; + for (auto &bala : bales_) { + bala.inicialitzar(); } } void JocAsteroides::actualitzar(float delta_time) { - // Actualització de la física de la nau (TIME-BASED) - // Basat en el codi Pascal original: lines 394-417 - // Convertit a time-based per ser independent del framerate - // Constants de física ara definides a core/defaults.hpp (Defaults::Physics) - - // Obtenir estat actual del teclat (no events, sinó estat continu) - const bool *keyboard_state = SDL_GetKeyboardState(nullptr); - - // Processar input continu (com teclapuls() del Pascal original) - if (keyboard_state[SDL_SCANCODE_RIGHT]) { - nau_.angle += Defaults::Physics::ROTATION_SPEED * delta_time; - } - - if (keyboard_state[SDL_SCANCODE_LEFT]) { - nau_.angle -= Defaults::Physics::ROTATION_SPEED * delta_time; - } - - if (keyboard_state[SDL_SCANCODE_UP]) { - if (nau_.velocitat < Defaults::Physics::MAX_VELOCITY) { - nau_.velocitat += Defaults::Physics::ACCELERATION * delta_time; - if (nau_.velocitat > Defaults::Physics::MAX_VELOCITY) { - nau_.velocitat = Defaults::Physics::MAX_VELOCITY; - } - } - } - - // Calcular nova posició basada en velocitat i angle - // S'usa (angle - PI/2) perquè angle=0 apunte cap amunt, no cap a la dreta - // velocitat està en px/s, així que multipliquem per delta_time - float dy = (nau_.velocitat * delta_time) * - std::sin(nau_.angle - Constants::PI / 2.0f) + - nau_.centre.y; - float dx = (nau_.velocitat * delta_time) * - std::cos(nau_.angle - Constants::PI / 2.0f) + - nau_.centre.x; - - // Boundary checking - només actualitzar si dins dels marges - // Acumulació directa amb precisió subpíxel - if (dy > Constants::MARGE_DALT && dy < Constants::MARGE_BAIX) { - nau_.centre.y = dy; - } - - if (dx > Constants::MARGE_ESQ && dx < Constants::MARGE_DRET) { - nau_.centre.x = dx; - } - - // Fricció - desacceleració gradual (time-based) - if (nau_.velocitat > 0.1f) { - nau_.velocitat -= Defaults::Physics::FRICTION * delta_time; - if (nau_.velocitat < 0.0f) { - nau_.velocitat = 0.0f; - } - } + // Actualitzar nau (input + física) + nau_.processar_input(delta_time); + nau_.actualitzar(delta_time); // Actualitzar moviment i rotació dels enemics (ORNIs) - // Basat en el codi Pascal original: lines 429-432 for (auto &enemy : orni_) { - if (enemy.esta) { - // Moviment autònom (Fase 8) - mou_orni(enemy, delta_time); - - // Rotació visual (time-based: drotacio està en rad/s) - enemy.rotacio += enemy.drotacio * delta_time; - } + enemy.actualitzar(delta_time); } // Actualitzar moviment de bales (Fase 9) for (auto &bala : bales_) { - if (bala.esta) { - mou_bales(bala, delta_time); - } + bala.actualitzar(delta_time); } } void JocAsteroides::dibuixar() { - // Dibuixar la nau si no està en seqüència de mort - if (itocado_ == 0) { - // Escalar velocitat per l'efect visual (120 px/s → ~6 px d'efecte) - // El codi Pascal original sumava velocitat (0-6) al radi per donar - // sensació de "empenta". Ara velocitat està en px/s (0-120). - float velocitat_visual = nau_.velocitat / 20.0f; - rota_tri(nau_, nau_.angle, velocitat_visual, true); - } + // Dibuixar nau + nau_.dibuixar(); // Dibuixar ORNIs (enemics) - // Basat en el codi Pascal original: lines 429-432 for (const auto &enemy : orni_) { - if (enemy.esta) { - rota_pol(enemy, enemy.rotacio, true); - } + enemy.dibuixar(); } // Dibuixar bales (Fase 9) for (const auto &bala : bales_) { - if (bala.esta) { - // Dibuixar com a pentàgon petit, sense rotació visual (sempre mateix - // angle) - rota_pol(bala, 0.0f, true); - } + bala.dibuixar(); } // TODO: Dibuixar marges (Fase 11) @@ -183,22 +91,8 @@ void JocAsteroides::processar_input(const SDL_Event &event) { // Buscar primera bala inactiva for (auto &bala : bales_) { - if (!bala.esta) { - // Activar bala - bala.esta = true; - - // Posició inicial = centre de la nau - bala.centre.x = nau_.centre.x; - bala.centre.y = nau_.centre.y; - - // Angle = angle de la nau (dispara en la direcció que apunta) - bala.angle = nau_.angle; - - // Velocitat alta (el joc Pascal original usava 7 px/frame) - // 7 px/frame × 20 FPS = 140 px/s - bala.velocitat = 140.0f; - - // Només una bala alhora (com el joc original) + if (!bala.esta_activa()) { + bala.disparar(nau_.get_centre(), nau_.get_angle()); break; } } @@ -210,214 +104,6 @@ void JocAsteroides::processar_input(const SDL_Event &event) { } } -// Funcions de dibuix - -bool JocAsteroides::linea(int x1, int y1, int x2, int y2, bool dibuixar) { - // Algorisme de Bresenham per dibuixar línies - // Basat en el codi Pascal original - - // Helper function: retorna el signe d'un nombre - auto sign = [](int x) -> int { - if (x < 0) - return -1; - if (x > 0) - return 1; - return 0; - }; - - // Variables per a l'algorisme (no utilitzades fins Fase 10 - detecció de - // col·lisions) int x = x1, y = y1; int xs = x2 - x1; int ys = y2 - y1; int xm - // = sign(xs); int ym = sign(ys); xs = std::abs(xs); ys = std::abs(ys); - - // Suprimir warning de variable no usada - (void)sign; - - // Detecció de col·lisió (TODO per Fase 10) - // El codi Pascal original llegia pixels del framebuffer bit-packed - // i comptava col·lisions. Per ara, usem SDL_RenderDrawLine i retornem false. - bool colisio = false; - - // Dibuixar amb SDL3 (més eficient que Bresenham píxel a píxel) - if (dibuixar && renderer_) { - SDL_SetRenderDrawColor(renderer_, 255, 255, 255, 255); // Blanc - SDL_RenderLine(renderer_, static_cast(x1), static_cast(y1), - static_cast(x2), static_cast(y2)); - } - - // Algorisme de Bresenham original (conservat per a futura detecció de - // col·lisió) - /* - if (xs > ys) { - // Línia plana (<45 graus) - int count = -(xs / 2); - while (x != x2) { - count = count + ys; - x = x + xm; - if (count > 0) { - y = y + ym; - count = count - xs; - } - // Aquí aniria la detecció de col·lisió píxel a píxel - } - } else { - // Línia pronunciada (>=45 graus) - int count = -(ys / 2); - while (y != y2) { - count = count + xs; - y = y + ym; - if (count > 0) { - x = x + xm; - count = count - ys; - } - // Aquí aniria la detecció de col·lisió píxel a píxel - } - } - */ - - return colisio; -} - -void JocAsteroides::rota_tri(const Triangle &tri, float angul, float velocitat, - bool dibuixar) { - // Rotar i dibuixar triangle (nau) - // Conversió de coordenades polars a cartesianes amb rotació - // Basat en el codi Pascal original: lines 271-284 - - // Convertir cada punt polar a cartesià - // x = (r + velocitat) * cos(angle_punt + angle_nau) + centre.x - // y = (r + velocitat) * sin(angle_punt + angle_nau) + centre.y - - int x1 = static_cast(std::round((tri.p1.r + velocitat) * - std::cos(tri.p1.angle + angul))) + - tri.centre.x; - - int y1 = static_cast(std::round((tri.p1.r + velocitat) * - std::sin(tri.p1.angle + angul))) + - tri.centre.y; - - int x2 = static_cast(std::round((tri.p2.r + velocitat) * - std::cos(tri.p2.angle + angul))) + - tri.centre.x; - - int y2 = static_cast(std::round((tri.p2.r + velocitat) * - std::sin(tri.p2.angle + angul))) + - tri.centre.y; - - int x3 = static_cast(std::round((tri.p3.r + velocitat) * - std::cos(tri.p3.angle + angul))) + - tri.centre.x; - - int y3 = static_cast(std::round((tri.p3.r + velocitat) * - std::sin(tri.p3.angle + angul))) + - tri.centre.y; - - // Dibuixar les 3 línies que formen el triangle - linea(x1, y1, x2, y2, dibuixar); - linea(x1, y1, x3, y3, dibuixar); - linea(x3, y3, x2, y2, dibuixar); -} - -void JocAsteroides::rota_pol(const Poligon &pol, float angul, bool dibuixar) { - // Rotar i dibuixar polígon (enemics i bales) - // Conversió de coordenades polars a cartesianes amb rotació - // Basat en el codi Pascal original: lines 286-296 - - // Array temporal per emmagatzemar punts convertits a cartesianes - std::array xy; - - // Convertir cada punt polar a cartesià - for (uint8_t i = 0; i < pol.n; i++) { - xy[i].x = static_cast(std::round( - pol.ipuntx[i].r * std::cos(pol.ipuntx[i].angle + angul))) + - pol.centre.x; - - xy[i].y = static_cast(std::round( - pol.ipuntx[i].r * std::sin(pol.ipuntx[i].angle + angul))) + - pol.centre.y; - } - - // Dibuixar línies entre punts consecutius - for (uint8_t i = 0; i < pol.n - 1; i++) { - linea(xy[i].x, xy[i].y, xy[i + 1].x, xy[i + 1].y, dibuixar); - } - - // Tancar el polígon (últim punt → primer punt) - linea(xy[pol.n - 1].x, xy[pol.n - 1].y, xy[0].x, xy[0].y, dibuixar); -} - -void JocAsteroides::mou_orni(Poligon &orni, float delta_time) { - // Moviment autònom d'ORNI (enemic pentàgon) - // Basat EXACTAMENT en el codi Pascal original: ASTEROID.PAS lines 279-293 - // - // IMPORTANT: El Pascal original NO té canvi aleatori continu! - // Només ajusta l'angle quan toca una paret. - - // Calcular nova posició PROPUESTA (time-based, però lògica Pascal) - // velocitat ja està en px/s (40 px/s), multiplicar per delta_time - float velocitat_efectiva = orni.velocitat * delta_time; - - // Calcular desplaçament (angle-PI/2 perquè angle=0 apunta amunt) - float dy = velocitat_efectiva * std::sin(orni.angle - Constants::PI / 2.0f); - float dx = velocitat_efectiva * std::cos(orni.angle - Constants::PI / 2.0f); - - float new_y = orni.centre.y + dy; - float new_x = orni.centre.x + dx; - - // Lògica Pascal: Actualitza Y si dins, sinó ajusta angle aleatòriament - // if (dy>marge_dalt) and (dy Constants::MARGE_DALT && new_y < Constants::MARGE_BAIX) { - orni.centre.y = new_y; - } else { - // Pequeño ajuste aleatorio: (random(256)/512)*(random(3)-1) - // random(256) = 0..255, /512 = 0..0.498 - // random(3) = 0,1,2, -1 = -1,0,1 - // Resultado: ±0.5 rad aprox - float rand1 = (static_cast(std::rand() % 256) / 512.0f); - int rand2 = (std::rand() % 3) - 1; // -1, 0, o 1 - orni.angle += rand1 * static_cast(rand2); - } - - // Lògica Pascal: Actualitza X si dins, sinó ajusta angle aleatòriament - // if (dx>marge_esq) and (dx Constants::MARGE_ESQ && new_x < Constants::MARGE_DRET) { - orni.centre.x = new_x; - } else { - float rand1 = (static_cast(std::rand() % 256) / 512.0f); - int rand2 = (std::rand() % 3) - 1; - orni.angle += rand1 * static_cast(rand2); - } - - // Nota: La rotació visual (orni.rotacio += orni.drotacio) ja es fa a - // actualitzar() -} - -void JocAsteroides::mou_bales(Poligon &bala, float delta_time) { - // Moviment rectilini de la bala - // Basat en el codi Pascal original: procedure mou_bales - - // Calcular nova posició (moviment polar time-based) - // velocitat ja està en px/s (140 px/s), només cal multiplicar per delta_time - float velocitat_efectiva = bala.velocitat * delta_time; - - // Calcular desplaçament (angle-PI/2 perquè angle=0 apunta amunt) - float dy = velocitat_efectiva * std::sin(bala.angle - Constants::PI / 2.0f); - float dx = velocitat_efectiva * std::cos(bala.angle - Constants::PI / 2.0f); - - // Acumulació directa amb precisió subpíxel - bala.centre.y += dy; - bala.centre.x += dx; - - // Desactivar si surt dels marges (no rebota com els ORNIs) - if (bala.centre.x < Constants::MARGE_ESQ || - bala.centre.x > Constants::MARGE_DRET || - bala.centre.y < Constants::MARGE_DALT || - bala.centre.y > Constants::MARGE_BAIX) { - bala.esta = false; - } -} - void JocAsteroides::tocado() { // TODO: Implementar seqüència de mort } diff --git a/source/game/joc_asteroides.hpp b/source/game/joc_asteroides.hpp index 061b091..bf9d00e 100644 --- a/source/game/joc_asteroides.hpp +++ b/source/game/joc_asteroides.hpp @@ -5,8 +5,12 @@ #ifndef JOC_ASTEROIDES_HPP #define JOC_ASTEROIDES_HPP +#include "core/rendering/polygon_renderer.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 @@ -26,21 +30,13 @@ private: SDL_Renderer *renderer_; // Estat del joc - Triangle nau_; - std::array orni_; - std::array bales_; + Nau nau_; + std::array orni_; + std::array bales_; Poligon chatarra_cosmica_; uint16_t itocado_; - // Funcions de dibuix - bool linea(int x1, int y1, int x2, int y2, bool dibuixar); - void rota_tri(const Triangle &tri, float angul, float velocitat, - bool dibuixar); - void rota_pol(const Poligon &pol, float angul, bool dibuixar); - - // Moviment - void mou_orni(Poligon &orni, float delta_time); - void mou_bales(Poligon &bala, float delta_time); + // Funcions privades void tocado(); };