214 lines
5.4 KiB
C++
214 lines
5.4 KiB
C++
// 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/rendering/line_renderer.hpp"
|
|
#include "../../core/system/gestor_escenes.hpp"
|
|
#include "../../core/system/global_events.hpp"
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
#include <ctime>
|
|
#include <iostream>
|
|
|
|
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;
|
|
}
|
|
|
|
// Events globals (F1/F2/F3/ESC/QUIT)
|
|
if (GlobalEvents::handle(event, sdl_)) {
|
|
continue;
|
|
}
|
|
|
|
// Processament específic del joc (SPACE per disparar)
|
|
processar_input(event);
|
|
}
|
|
|
|
// 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<unsigned>(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 marges de la zona de joc
|
|
dibuixar_marges();
|
|
|
|
// 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();
|
|
}
|
|
|
|
// Dibuixar marcador
|
|
dibuixar_marcador();
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
void EscenaJoc::dibuixar_marges() const {
|
|
// Dibuixar rectangle de la zona de joc
|
|
const SDL_FRect& zona = Defaults::Zones::GAME;
|
|
|
|
// Coordenades dels cantons
|
|
int x1 = static_cast<int>(zona.x);
|
|
int y1 = static_cast<int>(zona.y);
|
|
int x2 = static_cast<int>(zona.x + zona.w);
|
|
int y2 = static_cast<int>(zona.y + zona.h);
|
|
|
|
// 4 línies per formar el rectangle
|
|
Rendering::linea(sdl_.obte_renderer(), x1, y1, x2, y1, true); // Top
|
|
Rendering::linea(sdl_.obte_renderer(), x1, y2, x2, y2, true); // Bottom
|
|
Rendering::linea(sdl_.obte_renderer(), x1, y1, x1, y2, true); // Left
|
|
Rendering::linea(sdl_.obte_renderer(), x2, y1, x2, y2, true); // Right
|
|
}
|
|
|
|
void EscenaJoc::dibuixar_marcador() {
|
|
// Text estàtic (hardcoded)
|
|
const std::string text = "SCORE: 00000 LIFE: 3 LEVEL: 01";
|
|
|
|
// Escala ajustada per cabre en 640px d'amplada
|
|
// Zona marcador: width = 640 px, height = 64 px
|
|
// Text: 34 caràcters → necessitem ~487 px amb escala 1.2
|
|
// Altura caràcter: 20 * 1.2 = 24 px (37.5% de 64px)
|
|
const float escala = 1.2f;
|
|
const float spacing = 2.0f;
|
|
|
|
// Calcular amplada total del text
|
|
float text_width = text_.get_text_width(text, escala, spacing);
|
|
|
|
// Centrat horitzontal
|
|
float x = (Defaults::Zones::SCOREBOARD.w - text_width) / 2.0f;
|
|
|
|
// Centrat vertical
|
|
// Altura del caràcter escalat: 20 * 1.2 = 24 px
|
|
// Marge superior: (64 - 24) / 2 = 20 px
|
|
float y = Defaults::Zones::SCOREBOARD.y + 20.0f;
|
|
|
|
// Renderitzar
|
|
text_.render(text, {x, y}, escala, spacing);
|
|
}
|