Fase 1c: rename d'escenes i sistema d'escenes
Tots els tipus, fitxers, namespace, enums i metodes relacionats amb
les escenes passen del catala a l'angles seguint el .clang-tidy:
Fitxers (renames git):
- source/game/escenes/escena_joc.{hpp,cpp} -> game/scenes/game_scene.{hpp,cpp}
- source/game/escenes/escena_titol.{hpp,cpp} -> game/scenes/title_scene.{hpp,cpp}
- source/game/escenes/escena_logo.{hpp,cpp} -> game/scenes/logo_scene.{hpp,cpp}
- source/core/system/context_escenes.hpp -> core/system/scene_context.hpp
- Carpeta game/escenes/ -> game/scenes/
Tipus (CamelCase):
- EscenaJoc -> GameScene
- EscenaTitol -> TitleScene
- EscenaLogo -> LogoScene
- ContextEscenes -> SceneContext
- Escena (enum class) -> SceneType
- Opcio -> Option
- EstatGameOver -> GameOverState
- EstatTitol -> TitleState
- EstatAnimacio -> AnimationState
- ConfigPartida -> MatchConfig
Namespace:
- GestorEscenes -> SceneManager
Valors d'enum SceneType:
- TITOL -> TITLE
- JOC -> GAME
- EIXIR -> EXIT
(LOGO mantingut)
Metodes (camelBack):
- executar -> run
- canviar_escena -> setNextScene
- escena_desti -> nextScene
- opcio (getter) -> option
- consumir_opcio -> consumeOption
- reset_opcio -> resetOption
- set_config_partida -> setMatchConfig
- get_config_partida -> getMatchConfig
Camps privats (lower_case_):
- escena_desti_ -> next_scene_
- opcio_ -> option_
- config_partida_ -> match_config_
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,81 +0,0 @@
|
||||
// context_escenes.hpp - Sistema de gestió d'escenes i context de transicions
|
||||
// © 2025 Port a C++20
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/system/game_config.hpp"
|
||||
|
||||
namespace GestorEscenes {
|
||||
|
||||
// Context de transició entre escenes
|
||||
// Conté l'escena destinació i opcions específiques per aquella escena
|
||||
class ContextEscenes {
|
||||
public:
|
||||
// Tipus d'escena del joc
|
||||
enum class Escena {
|
||||
LOGO, // Pantalla d'inici (logo JAILGAMES)
|
||||
TITOL, // Pantalla de títol amb menú
|
||||
JOC, // Joc principal (Asteroids)
|
||||
EIXIR // Sortir del programa
|
||||
};
|
||||
|
||||
// Opcions específiques per a cada escena
|
||||
enum class Opcio {
|
||||
NONE, // Sense opcions especials (comportament per defecte)
|
||||
JUMP_TO_TITLE_MAIN, // TITOL: Saltar directament a MAIN (starfield instantani)
|
||||
// MODE_DEMO, // JOC: Mode demostració amb IA (futur)
|
||||
};
|
||||
|
||||
// Constructor inicial amb escena LOGO i sense opcions
|
||||
ContextEscenes() = default;
|
||||
|
||||
// Canviar escena amb opció específica
|
||||
void canviar_escena(Escena nova_escena, Opcio opcio = Opcio::NONE) {
|
||||
escena_desti_ = nova_escena;
|
||||
opcio_ = opcio;
|
||||
}
|
||||
|
||||
// Consultar escena destinació
|
||||
[[nodiscard]] auto escena_desti() const -> Escena {
|
||||
return escena_desti_;
|
||||
}
|
||||
|
||||
// Consultar opció actual
|
||||
[[nodiscard]] auto opcio() const -> Opcio {
|
||||
return opcio_;
|
||||
}
|
||||
|
||||
// Consumir opció (retorna valor i reseteja a NONE)
|
||||
// Utilitzar quan l'escena processa l'opció
|
||||
[[nodiscard]] auto consumir_opcio() -> Opcio {
|
||||
Opcio valor = opcio_;
|
||||
opcio_ = Opcio::NONE;
|
||||
return valor;
|
||||
}
|
||||
|
||||
// Reset opció a NONE (sense retornar valor)
|
||||
void reset_opcio() {
|
||||
opcio_ = Opcio::NONE;
|
||||
}
|
||||
|
||||
// Configurar partida abans de transicionar a JOC
|
||||
void set_config_partida(const GameConfig::ConfigPartida& config) {
|
||||
config_partida_ = config;
|
||||
}
|
||||
|
||||
// Obtenir configuració de partida (consumit per EscenaJoc)
|
||||
[[nodiscard]] const GameConfig::ConfigPartida& get_config_partida() const {
|
||||
return config_partida_;
|
||||
}
|
||||
|
||||
private:
|
||||
Escena escena_desti_{Escena::LOGO}; // Escena a la qual transicionar
|
||||
Opcio opcio_{Opcio::NONE}; // Opció específica per l'escena
|
||||
GameConfig::ConfigPartida config_partida_; // Configuració de partida (jugadors actius, mode)
|
||||
};
|
||||
|
||||
// Variable global inline per gestionar l'escena actual (backward compatibility)
|
||||
// Sincronitzada amb context.escena_desti() pel Director
|
||||
inline ContextEscenes::Escena actual = ContextEscenes::Escena::LOGO;
|
||||
|
||||
} // namespace GestorEscenes
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "context_escenes.hpp"
|
||||
#include "scene_context.hpp"
|
||||
#include "core/audio/audio.hpp"
|
||||
#include "core/audio/audio_cache.hpp"
|
||||
#include "core/defaults.hpp"
|
||||
@@ -17,9 +17,9 @@
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "core/resources/resource_loader.hpp"
|
||||
#include "core/utils/path_utils.hpp"
|
||||
#include "game/escenes/escena_joc.hpp"
|
||||
#include "game/escenes/escena_logo.hpp"
|
||||
#include "game/escenes/escena_titol.hpp"
|
||||
#include "game/scenes/game_scene.hpp"
|
||||
#include "game/scenes/logo_scene.hpp"
|
||||
#include "game/scenes/title_scene.hpp"
|
||||
#include "game/options.hpp"
|
||||
#include "project.h"
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
#endif
|
||||
|
||||
// Using declarations per simplificar el codi
|
||||
using GestorEscenes::ContextEscenes;
|
||||
using Escena = ContextEscenes::Escena;
|
||||
using SceneManager::SceneContext;
|
||||
using SceneType = SceneContext::SceneType;
|
||||
|
||||
// Constructor
|
||||
Director::Director(std::vector<std::string> const& args) {
|
||||
@@ -238,35 +238,35 @@ auto Director::run() -> int {
|
||||
}
|
||||
|
||||
// Crear context d'escenes
|
||||
ContextEscenes context;
|
||||
SceneContext context;
|
||||
#ifdef _DEBUG
|
||||
context.canviar_escena(Escena::TITOL);
|
||||
context.setNextScene(SceneType::TITLE);
|
||||
#else
|
||||
context.canviar_escena(Escena::LOGO);
|
||||
context.setNextScene(SceneType::LOGO);
|
||||
#endif
|
||||
|
||||
// Bucle principal de gestió d'escenes
|
||||
while (context.escena_desti() != Escena::EIXIR) {
|
||||
// Sincronitzar GestorEscenes::actual amb context
|
||||
// (altres sistemes encara poden llegir GestorEscenes::actual)
|
||||
GestorEscenes::actual = context.escena_desti();
|
||||
while (context.nextScene() != SceneType::EXIT) {
|
||||
// Sincronitzar SceneManager::actual amb context
|
||||
// (altres sistemes encara poden llegir SceneManager::actual)
|
||||
SceneManager::actual = context.nextScene();
|
||||
|
||||
switch (context.escena_desti()) {
|
||||
case Escena::LOGO: {
|
||||
EscenaLogo logo(sdl, context);
|
||||
logo.executar();
|
||||
switch (context.nextScene()) {
|
||||
case SceneType::LOGO: {
|
||||
LogoScene logo(sdl, context);
|
||||
logo.run();
|
||||
break;
|
||||
}
|
||||
|
||||
case Escena::TITOL: {
|
||||
EscenaTitol titol(sdl, context);
|
||||
titol.executar();
|
||||
case SceneType::TITLE: {
|
||||
TitleScene titol(sdl, context);
|
||||
titol.run();
|
||||
break;
|
||||
}
|
||||
|
||||
case Escena::JOC: {
|
||||
EscenaJoc joc(sdl, context);
|
||||
joc.executar();
|
||||
case SceneType::GAME: {
|
||||
GameScene joc(sdl, context);
|
||||
joc.run();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -275,8 +275,8 @@ auto Director::run() -> int {
|
||||
}
|
||||
}
|
||||
|
||||
// Sincronitzar final amb GestorEscenes::actual
|
||||
GestorEscenes::actual = Escena::EIXIR;
|
||||
// Sincronitzar final amb SceneManager::actual
|
||||
SceneManager::actual = SceneType::EXIT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ enum class Mode {
|
||||
};
|
||||
|
||||
// Configuració d'una partida
|
||||
struct ConfigPartida {
|
||||
struct MatchConfig {
|
||||
bool jugador1_actiu{false}; // És actiu el jugador 1?
|
||||
bool jugador2_actiu{false}; // És actiu el jugador 2?
|
||||
Mode mode{Mode::NORMAL}; // Mode de joc
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "context_escenes.hpp"
|
||||
#include "scene_context.hpp"
|
||||
#include "core/input/input.hpp"
|
||||
#include "core/input/mouse.hpp"
|
||||
#include "core/rendering/sdl_manager.hpp"
|
||||
|
||||
// Using declarations per simplificar el codi
|
||||
using GestorEscenes::ContextEscenes;
|
||||
using Escena = ContextEscenes::Escena;
|
||||
using SceneManager::SceneContext;
|
||||
using SceneType = SceneContext::SceneType;
|
||||
|
||||
namespace GlobalEvents {
|
||||
|
||||
bool handle(const SDL_Event& event, SDLManager& sdl, ContextEscenes& context) {
|
||||
bool handle(const SDL_Event& event, SDLManager& sdl, SceneContext& context) {
|
||||
// 1. Permitir que Input procese el evento (para hotplug de gamepads)
|
||||
auto event_msg = Input::get()->handleEvent(event);
|
||||
if (!event_msg.empty()) {
|
||||
@@ -25,8 +25,8 @@ bool handle(const SDL_Event& event, SDLManager& sdl, ContextEscenes& context) {
|
||||
|
||||
// 2. Procesar SDL_EVENT_QUIT directamente (no es input de juego)
|
||||
if (event.type == SDL_EVENT_QUIT) {
|
||||
context.canviar_escena(Escena::EIXIR);
|
||||
GestorEscenes::actual = Escena::EIXIR;
|
||||
context.setNextScene(SceneType::EXIT);
|
||||
SceneManager::actual = SceneType::EXIT;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ bool handle(const SDL_Event& event, SDLManager& sdl, ContextEscenes& context) {
|
||||
return true;
|
||||
|
||||
case SDL_SCANCODE_ESCAPE:
|
||||
context.canviar_escena(Escena::EIXIR);
|
||||
GestorEscenes::actual = Escena::EIXIR;
|
||||
context.setNextScene(SceneType::EXIT);
|
||||
SceneManager::actual = SceneType::EXIT;
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
// Forward declarations
|
||||
class SDLManager;
|
||||
namespace GestorEscenes {
|
||||
class ContextEscenes;
|
||||
namespace SceneManager {
|
||||
class SceneContext;
|
||||
}
|
||||
|
||||
namespace GlobalEvents {
|
||||
// Processa events globals (F1/F2/F3/ESC/QUIT)
|
||||
// Retorna true si l'event ha estat processat i no cal seguir processant-lo
|
||||
bool handle(const SDL_Event& event, SDLManager& sdl, GestorEscenes::ContextEscenes& context);
|
||||
bool handle(const SDL_Event& event, SDLManager& sdl, SceneManager::SceneContext& context);
|
||||
} // namespace GlobalEvents
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
// context_escenes.hpp - Sistema de gestió d'escenes i context de transicions
|
||||
// © 2025 Port a C++20
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/system/game_config.hpp"
|
||||
|
||||
namespace SceneManager {
|
||||
|
||||
// Context de transició entre escenes
|
||||
// Conté l'escena destinació i opcions específiques per aquella escena
|
||||
class SceneContext {
|
||||
public:
|
||||
// Tipus d'escena del joc
|
||||
enum class SceneType {
|
||||
LOGO, // Pantalla d'inici (logo JAILGAMES)
|
||||
TITLE, // Pantalla de títol amb menú
|
||||
GAME, // Joc principal (Asteroids)
|
||||
EXIT // Sortir del programa
|
||||
};
|
||||
|
||||
// Opcions específiques per a cada escena
|
||||
enum class Option {
|
||||
NONE, // Sense opcions especials (comportament per defecte)
|
||||
JUMP_TO_TITLE_MAIN, // TITLE: Saltar directament a MAIN (starfield instantani)
|
||||
// MODE_DEMO, // GAME: Mode demostració amb IA (futur)
|
||||
};
|
||||
|
||||
// Constructor inicial amb escena LOGO i sense opcions
|
||||
SceneContext() = default;
|
||||
|
||||
// Canviar escena amb opció específica
|
||||
void setNextScene(SceneType next_scene, Option option = Option::NONE) {
|
||||
next_scene_ = next_scene;
|
||||
option_ = option;
|
||||
}
|
||||
|
||||
// Consultar escena destinació
|
||||
[[nodiscard]] auto nextScene() const -> SceneType {
|
||||
return next_scene_;
|
||||
}
|
||||
|
||||
// Consultar opció actual
|
||||
[[nodiscard]] auto option() const -> Option {
|
||||
return option_;
|
||||
}
|
||||
|
||||
// Consumir opció (retorna valor i reseteja a NONE)
|
||||
// Utilitzar quan l'escena processa l'opció
|
||||
[[nodiscard]] auto consumeOption() -> Option {
|
||||
Option valor = option_;
|
||||
option_ = Option::NONE;
|
||||
return valor;
|
||||
}
|
||||
|
||||
// Reset opció a NONE (sense retornar valor)
|
||||
void resetOption() {
|
||||
option_ = Option::NONE;
|
||||
}
|
||||
|
||||
// Configurar partida abans de transicionar a GAME
|
||||
void setMatchConfig(const GameConfig::MatchConfig& config) {
|
||||
match_config_ = config;
|
||||
}
|
||||
|
||||
// Obtenir configuració de partida (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 partida (jugadors actius, mode)
|
||||
};
|
||||
|
||||
// Variable global inline per gestionar l'escena actual (backward compatibility)
|
||||
// Sincronitzada amb context.nextScene() pel Director
|
||||
inline SceneContext::SceneType actual = SceneContext::SceneType::LOGO;
|
||||
|
||||
} // namespace SceneManager
|
||||
@@ -2,7 +2,7 @@
|
||||
// © 1999 Visente i Sergi (versió Pascal)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
|
||||
#include "escena_joc.hpp"
|
||||
#include "game_scene.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
@@ -18,16 +18,16 @@
|
||||
#include "core/math/easing.hpp"
|
||||
#include "core/physics/collision.hpp"
|
||||
#include "core/rendering/line_renderer.hpp"
|
||||
#include "core/system/context_escenes.hpp"
|
||||
#include "core/system/scene_context.hpp"
|
||||
#include "core/system/global_events.hpp"
|
||||
#include "game/stage_system/stage_loader.hpp"
|
||||
|
||||
// Using declarations per simplificar el codi
|
||||
using GestorEscenes::ContextEscenes;
|
||||
using Escena = ContextEscenes::Escena;
|
||||
using Opcio = ContextEscenes::Opcio;
|
||||
using SceneManager::SceneContext;
|
||||
using SceneType = SceneContext::SceneType;
|
||||
using Option = SceneContext::Option;
|
||||
|
||||
EscenaJoc::EscenaJoc(SDLManager& sdl, ContextEscenes& context)
|
||||
GameScene::GameScene(SDLManager& sdl, SceneContext& context)
|
||||
: sdl_(sdl),
|
||||
context_(context),
|
||||
debris_manager_(sdl.obte_renderer()),
|
||||
@@ -35,18 +35,18 @@ EscenaJoc::EscenaJoc(SDLManager& sdl, ContextEscenes& context)
|
||||
text_(sdl.obte_renderer()),
|
||||
init_hud_rect_sound_played_(false) {
|
||||
// Recuperar configuració de partida des del context
|
||||
config_partida_ = context_.get_config_partida();
|
||||
match_config_ = context_.getMatchConfig();
|
||||
|
||||
// Debug output de la configuració
|
||||
std::cout << "[EscenaJoc] Configuració de partida - P1: "
|
||||
<< (config_partida_.jugador1_actiu ? "ACTIU" : "INACTIU")
|
||||
std::cout << "[GameScene] Configuració de partida - P1: "
|
||||
<< (match_config_.jugador1_actiu ? "ACTIU" : "INACTIU")
|
||||
<< ", P2: "
|
||||
<< (config_partida_.jugador2_actiu ? "ACTIU" : "INACTIU")
|
||||
<< (match_config_.jugador2_actiu ? "ACTIU" : "INACTIU")
|
||||
<< '\n';
|
||||
|
||||
// Consumir opcions (preparació per MODE_DEMO futur)
|
||||
auto opcio = context_.consumir_opcio();
|
||||
(void)opcio; // Suprimir warning de variable no usada
|
||||
auto option = context_.consumeOption();
|
||||
(void)option; // Suprimir warning de variable no usada
|
||||
|
||||
// Inicialitzar naus amb renderer (P1=ship.shp, P2=ship2.shp)
|
||||
naus_[0] = Ship(sdl.obte_renderer(), "ship.shp"); // Jugador 1: nave estàndar
|
||||
@@ -63,8 +63,8 @@ EscenaJoc::EscenaJoc(SDLManager& sdl, ContextEscenes& context)
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaJoc::executar() {
|
||||
std::cout << "Escena Joc: Inicialitzant...\n";
|
||||
void GameScene::run() {
|
||||
std::cout << "SceneType Joc: Inicialitzant...\n";
|
||||
|
||||
// Inicialitzar estat del joc
|
||||
init();
|
||||
@@ -72,7 +72,7 @@ void EscenaJoc::executar() {
|
||||
SDL_Event event;
|
||||
Uint64 last_time = SDL_GetTicks();
|
||||
|
||||
while (GestorEscenes::actual == Escena::JOC) {
|
||||
while (SceneManager::actual == SceneType::GAME) {
|
||||
// Calcular delta_time real
|
||||
Uint64 current_time = SDL_GetTicks();
|
||||
float delta_time = (current_time - last_time) / 1000.0F;
|
||||
@@ -123,10 +123,10 @@ void EscenaJoc::executar() {
|
||||
sdl_.presenta();
|
||||
}
|
||||
|
||||
std::cout << "Escena Joc: Finalitzant...\n";
|
||||
std::cout << "SceneType Joc: Finalitzant...\n";
|
||||
}
|
||||
|
||||
void EscenaJoc::init() {
|
||||
void GameScene::init() {
|
||||
// Inicialitzar generador de números aleatoris
|
||||
// Basat en el codi Pascal original: line 376
|
||||
std::srand(static_cast<unsigned>(std::time(nullptr)));
|
||||
@@ -135,7 +135,7 @@ void EscenaJoc::init() {
|
||||
if (!stage_config_) {
|
||||
stage_config_ = StageSystem::StageLoader::carregar("data/stages/stages.yaml");
|
||||
if (!stage_config_) {
|
||||
std::cerr << "[EscenaJoc] Error: no s'ha pogut carregar stages.yaml" << '\n';
|
||||
std::cerr << "[GameScene] Error: no s'ha pogut carregar stages.yaml" << '\n';
|
||||
// Continue without stage system (will crash, but helps debugging)
|
||||
}
|
||||
}
|
||||
@@ -154,7 +154,7 @@ void EscenaJoc::init() {
|
||||
// Initialize lives and game over state (independent lives per player)
|
||||
vides_per_jugador_[0] = Defaults::Game::STARTING_LIVES;
|
||||
vides_per_jugador_[1] = Defaults::Game::STARTING_LIVES;
|
||||
estat_game_over_ = EstatGameOver::NONE;
|
||||
estat_game_over_ = GameOverState::NONE;
|
||||
continue_counter_ = 0;
|
||||
continue_tick_timer_ = 0.0F;
|
||||
continues_usados_ = 0;
|
||||
@@ -172,19 +172,19 @@ void EscenaJoc::init() {
|
||||
|
||||
// Inicialitzar naus segons configuració (només jugadors actius)
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
bool jugador_actiu = (i == 0) ? config_partida_.jugador1_actiu : config_partida_.jugador2_actiu;
|
||||
bool jugador_actiu = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu;
|
||||
|
||||
if (jugador_actiu) {
|
||||
// Jugador actiu: init normalment
|
||||
Vec2 spawn_pos = obtenir_punt_spawn(i);
|
||||
naus_[i].init(&spawn_pos, false); // No invulnerability at start
|
||||
std::cout << "[EscenaJoc] Jugador " << (i + 1) << " inicialitzat\n";
|
||||
std::cout << "[GameScene] Jugador " << (i + 1) << " inicialitzat\n";
|
||||
} else {
|
||||
// Jugador inactiu: marcar com a mort permanent
|
||||
naus_[i].markHit();
|
||||
itocado_per_jugador_[i] = 999.0F; // Valor sentinella (permanent inactiu)
|
||||
vides_per_jugador_[i] = 0; // Sense vides
|
||||
std::cout << "[EscenaJoc] Jugador " << (i + 1) << " inactiu\n";
|
||||
std::cout << "[GameScene] Jugador " << (i + 1) << " inactiu\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,20 +208,20 @@ void EscenaJoc::init() {
|
||||
init_hud_rect_sound_played_ = false;
|
||||
}
|
||||
|
||||
void EscenaJoc::update(float delta_time) {
|
||||
void GameScene::update(float delta_time) {
|
||||
// Processar disparos (state-based, no event-based)
|
||||
if (estat_game_over_ == EstatGameOver::NONE) {
|
||||
if (estat_game_over_ == GameOverState::NONE) {
|
||||
auto* input = Input::get();
|
||||
|
||||
// Jugador 1 dispara (només si està actiu)
|
||||
if (config_partida_.jugador1_actiu) {
|
||||
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à actiu)
|
||||
if (config_partida_.jugador2_actiu) {
|
||||
if (match_config_.jugador2_actiu) {
|
||||
if (input->checkActionPlayer2(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||
disparar_bala(1);
|
||||
}
|
||||
@@ -232,17 +232,17 @@ void EscenaJoc::update(float delta_time) {
|
||||
if (stage_manager_->get_estat() == StageSystem::EstatStage::PLAYING) {
|
||||
// Check if at least one player is alive and playing (game in progress)
|
||||
bool algun_jugador_viu = false;
|
||||
if (config_partida_.jugador1_actiu && itocado_per_jugador_[0] != 999.0F) {
|
||||
if (match_config_.jugador1_actiu && itocado_per_jugador_[0] != 999.0F) {
|
||||
algun_jugador_viu = true;
|
||||
}
|
||||
if (config_partida_.jugador2_actiu && itocado_per_jugador_[1] != 999.0F) {
|
||||
if (match_config_.jugador2_actiu && itocado_per_jugador_[1] != 999.0F) {
|
||||
algun_jugador_viu = true;
|
||||
}
|
||||
|
||||
// Only allow join if there's an active game
|
||||
if (algun_jugador_viu) {
|
||||
// P2 can join if not currently playing (never joined OR dead without lives)
|
||||
bool p2_no_juga = !config_partida_.jugador2_actiu || // Never joined
|
||||
bool p2_no_juga = !match_config_.jugador2_actiu || // Never joined
|
||||
itocado_per_jugador_[1] == 999.0F; // Dead without lives
|
||||
|
||||
if (p2_no_juga) {
|
||||
@@ -252,7 +252,7 @@ void EscenaJoc::update(float delta_time) {
|
||||
}
|
||||
|
||||
// P1 can join if not currently playing (never joined OR dead without lives)
|
||||
bool p1_no_juga = !config_partida_.jugador1_actiu || // Never joined
|
||||
bool p1_no_juga = !match_config_.jugador1_actiu || // Never joined
|
||||
itocado_per_jugador_[0] == 999.0F; // Dead without lives
|
||||
|
||||
if (p1_no_juga) {
|
||||
@@ -265,7 +265,7 @@ void EscenaJoc::update(float delta_time) {
|
||||
}
|
||||
|
||||
// Handle CONTINUE screen
|
||||
if (estat_game_over_ == EstatGameOver::CONTINUE) {
|
||||
if (estat_game_over_ == GameOverState::CONTINUE) {
|
||||
actualitzar_continue(delta_time);
|
||||
processar_input_continue();
|
||||
|
||||
@@ -282,7 +282,7 @@ void EscenaJoc::update(float delta_time) {
|
||||
}
|
||||
|
||||
// Handle final GAME OVER state
|
||||
if (estat_game_over_ == EstatGameOver::GAME_OVER) {
|
||||
if (estat_game_over_ == GameOverState::GAME_OVER) {
|
||||
// Game over: only update timer, enemies, bullets, and debris
|
||||
game_over_timer_ -= delta_time;
|
||||
|
||||
@@ -290,8 +290,8 @@ void EscenaJoc::update(float delta_time) {
|
||||
// Aturar música de joc abans de tornar al títol
|
||||
Audio::get()->stopMusic();
|
||||
// Transició a pantalla de títol
|
||||
context_.canviar_escena(Escena::TITOL);
|
||||
GestorEscenes::actual = Escena::TITOL;
|
||||
context_.setNextScene(SceneType::TITLE);
|
||||
SceneManager::actual = SceneType::TITLE;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -335,11 +335,11 @@ void EscenaJoc::update(float delta_time) {
|
||||
itocado_per_jugador_[i] = 999.0F;
|
||||
|
||||
// Check if ALL ACTIVE players are dead (trigger continue screen)
|
||||
bool p1_dead = !config_partida_.jugador1_actiu || vides_per_jugador_[0] <= 0;
|
||||
bool p2_dead = !config_partida_.jugador2_actiu || vides_per_jugador_[1] <= 0;
|
||||
bool p1_dead = !match_config_.jugador1_actiu || vides_per_jugador_[0] <= 0;
|
||||
bool p2_dead = !match_config_.jugador2_actiu || vides_per_jugador_[1] <= 0;
|
||||
|
||||
if (p1_dead && p2_dead) {
|
||||
estat_game_over_ = EstatGameOver::CONTINUE;
|
||||
estat_game_over_ = GameOverState::CONTINUE;
|
||||
continue_counter_ = Defaults::Game::CONTINUE_COUNT_START;
|
||||
continue_tick_timer_ = Defaults::Game::CONTINUE_TICK_DURATION;
|
||||
}
|
||||
@@ -396,12 +396,12 @@ void EscenaJoc::update(float delta_time) {
|
||||
Defaults::Game::INIT_HUD_SHIP2_RATIO_END);
|
||||
|
||||
// [MODIFICAT] Animar AMBAS naus con sus progress respectivos
|
||||
if (config_partida_.jugador1_actiu && ship1_progress < 1.0F) {
|
||||
if (match_config_.jugador1_actiu && ship1_progress < 1.0F) {
|
||||
Vec2 pos_p1 = calcular_posicio_nau_init_hud(ship1_progress, 0);
|
||||
naus_[0].setCenter(pos_p1);
|
||||
}
|
||||
|
||||
if (config_partida_.jugador2_actiu && ship2_progress < 1.0F) {
|
||||
if (match_config_.jugador2_actiu && ship2_progress < 1.0F) {
|
||||
Vec2 pos_p2 = calcular_posicio_nau_init_hud(ship2_progress, 1);
|
||||
naus_[1].setCenter(pos_p2);
|
||||
}
|
||||
@@ -425,7 +425,7 @@ void EscenaJoc::update(float delta_time) {
|
||||
|
||||
// [NEW] Allow both ships movement and shooting during intro
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
bool jugador_actiu = (i == 0) ? config_partida_.jugador1_actiu : config_partida_.jugador2_actiu;
|
||||
bool jugador_actiu = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu;
|
||||
if (jugador_actiu && itocado_per_jugador_[i] == 0.0F) { // Only active, alive players
|
||||
naus_[i].processInput(delta_time, i);
|
||||
naus_[i].update(delta_time);
|
||||
@@ -460,7 +460,7 @@ void EscenaJoc::update(float delta_time) {
|
||||
|
||||
// [EXISTING] Normal gameplay - update active players
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
bool jugador_actiu = (i == 0) ? config_partida_.jugador1_actiu : config_partida_.jugador2_actiu;
|
||||
bool jugador_actiu = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu;
|
||||
if (jugador_actiu && itocado_per_jugador_[i] == 0.0F) { // Only active, alive players
|
||||
naus_[i].processInput(delta_time, i);
|
||||
naus_[i].update(delta_time);
|
||||
@@ -489,7 +489,7 @@ void EscenaJoc::update(float delta_time) {
|
||||
|
||||
// [NEW] Allow both ships movement and shooting during outro
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
bool jugador_actiu = (i == 0) ? config_partida_.jugador1_actiu : config_partida_.jugador2_actiu;
|
||||
bool jugador_actiu = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu;
|
||||
if (jugador_actiu && itocado_per_jugador_[i] == 0.0F) { // Only active, alive players
|
||||
naus_[i].processInput(delta_time, i);
|
||||
naus_[i].update(delta_time);
|
||||
@@ -508,9 +508,9 @@ void EscenaJoc::update(float delta_time) {
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaJoc::draw() {
|
||||
void GameScene::draw() {
|
||||
// Handle CONTINUE screen
|
||||
if (estat_game_over_ == EstatGameOver::CONTINUE) {
|
||||
if (estat_game_over_ == GameOverState::CONTINUE) {
|
||||
// Draw game background elements first
|
||||
dibuixar_marges();
|
||||
|
||||
@@ -532,7 +532,7 @@ void EscenaJoc::draw() {
|
||||
}
|
||||
|
||||
// Handle final GAME OVER state
|
||||
if (estat_game_over_ == EstatGameOver::GAME_OVER) {
|
||||
if (estat_game_over_ == GameOverState::GAME_OVER) {
|
||||
// Game over: draw enemies, bullets, debris, and "GAME OVER" text
|
||||
dibuixar_marges();
|
||||
|
||||
@@ -610,11 +610,11 @@ void EscenaJoc::draw() {
|
||||
}
|
||||
|
||||
// [MODIFICAT] Dibuixar naus amb progress independent
|
||||
if (ship1_progress > 0.0F && config_partida_.jugador1_actiu && !naus_[0].isHit()) {
|
||||
if (ship1_progress > 0.0F && match_config_.jugador1_actiu && !naus_[0].isHit()) {
|
||||
naus_[0].draw();
|
||||
}
|
||||
|
||||
if (ship2_progress > 0.0F && config_partida_.jugador2_actiu && !naus_[1].isHit()) {
|
||||
if (ship2_progress > 0.0F && match_config_.jugador2_actiu && !naus_[1].isHit()) {
|
||||
naus_[1].draw();
|
||||
}
|
||||
|
||||
@@ -625,7 +625,7 @@ void EscenaJoc::draw() {
|
||||
dibuixar_marges();
|
||||
// [NEW] Draw both ships if active and alive
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
bool jugador_actiu = (i == 0) ? config_partida_.jugador1_actiu : config_partida_.jugador2_actiu;
|
||||
bool jugador_actiu = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu;
|
||||
if (jugador_actiu && itocado_per_jugador_[i] == 0.0F) {
|
||||
naus_[i].draw();
|
||||
}
|
||||
@@ -650,7 +650,7 @@ void EscenaJoc::draw() {
|
||||
|
||||
// [EXISTING] Normal rendering - active ships
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
bool jugador_actiu = (i == 0) ? config_partida_.jugador1_actiu : config_partida_.jugador2_actiu;
|
||||
bool jugador_actiu = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu;
|
||||
if (jugador_actiu && itocado_per_jugador_[i] == 0.0F) {
|
||||
naus_[i].draw();
|
||||
}
|
||||
@@ -673,7 +673,7 @@ void EscenaJoc::draw() {
|
||||
dibuixar_marges();
|
||||
// [NEW] Draw both ships if active and alive
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
bool jugador_actiu = (i == 0) ? config_partida_.jugador1_actiu : config_partida_.jugador2_actiu;
|
||||
bool jugador_actiu = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu;
|
||||
if (jugador_actiu && itocado_per_jugador_[i] == 0.0F) {
|
||||
naus_[i].draw();
|
||||
}
|
||||
@@ -695,7 +695,7 @@ void EscenaJoc::draw() {
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaJoc::tocado(uint8_t player_id) {
|
||||
void GameScene::tocado(uint8_t player_id) {
|
||||
// Death sequence: 3 phases
|
||||
// Phase 1: First call (itocado_per_jugador_[player_id] == 0) - trigger explosion
|
||||
// Phase 2: Animation (0 < itocado_ < 3.0s) - debris animation
|
||||
@@ -734,7 +734,7 @@ void EscenaJoc::tocado(uint8_t player_id) {
|
||||
// Phase 3 is handled in update() when itocado_per_jugador_ >= DEATH_DURATION
|
||||
}
|
||||
|
||||
void EscenaJoc::dibuixar_marges() const {
|
||||
void GameScene::dibuixar_marges() const {
|
||||
// Dibuixar rectangle de la zona de joc
|
||||
const SDL_FRect& zona = Defaults::Zones::PLAYAREA;
|
||||
|
||||
@@ -751,7 +751,7 @@ void EscenaJoc::dibuixar_marges() const {
|
||||
Rendering::linea(sdl_.obte_renderer(), x2, y1, x2, y2); // Right
|
||||
}
|
||||
|
||||
void EscenaJoc::dibuixar_marcador() {
|
||||
void GameScene::dibuixar_marcador() {
|
||||
// Construir text del marcador
|
||||
std::string text = construir_marcador();
|
||||
|
||||
@@ -768,7 +768,7 @@ void EscenaJoc::dibuixar_marcador() {
|
||||
text_.render_centered(text, {.x = centre_x, .y = centre_y}, escala, spacing);
|
||||
}
|
||||
|
||||
void EscenaJoc::dibuixar_marges_animat(float progress) const {
|
||||
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
|
||||
|
||||
@@ -827,7 +827,7 @@ void EscenaJoc::dibuixar_marges_animat(float progress) const {
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaJoc::dibuixar_marcador_animat(float progress) {
|
||||
void GameScene::dibuixar_marcador_animat(float progress) {
|
||||
// Animació del marcador pujant des de baix amb easing
|
||||
|
||||
// Calcular progrés amb easing
|
||||
@@ -855,7 +855,7 @@ void EscenaJoc::dibuixar_marcador_animat(float progress) {
|
||||
text_.render_centered(text, {.x = centre_x, .y = centre_y_animada}, escala, spacing);
|
||||
}
|
||||
|
||||
Vec2 EscenaJoc::calcular_posicio_nau_init_hud(float progress, uint8_t player_id) const {
|
||||
Vec2 GameScene::calcular_posicio_nau_init_hud(float progress, uint8_t player_id) const {
|
||||
// Animació de la nau pujant des de baix amb easing
|
||||
// [MODIFICAT] Ambas naves usan ease_out_quad (desfase temporal via INIT/END)
|
||||
|
||||
@@ -879,7 +879,7 @@ Vec2 EscenaJoc::calcular_posicio_nau_init_hud(float progress, uint8_t player_id)
|
||||
return {.x = x_final, .y = y_animada};
|
||||
}
|
||||
|
||||
float EscenaJoc::calcular_progress_rango(float global_progress, float ratio_init, float ratio_end) const {
|
||||
float GameScene::calcular_progress_rango(float global_progress, float ratio_init, float ratio_end) const {
|
||||
// Convierte global_progress (0.0→1.0) a element_progress usando ventana [INIT, END]
|
||||
//
|
||||
// Casos:
|
||||
@@ -904,11 +904,11 @@ float EscenaJoc::calcular_progress_rango(float global_progress, float ratio_init
|
||||
return (global_progress - ratio_init) / (ratio_end - ratio_init);
|
||||
}
|
||||
|
||||
std::string EscenaJoc::construir_marcador() const {
|
||||
std::string GameScene::construir_marcador() const {
|
||||
// Puntuació P1 (6 dígits) - mostrar zeros si inactiu
|
||||
std::string score_p1;
|
||||
std::string vides_p1;
|
||||
if (config_partida_.jugador1_actiu) {
|
||||
if (match_config_.jugador1_actiu) {
|
||||
score_p1 = std::to_string(puntuacio_per_jugador_[0]);
|
||||
score_p1 = std::string(6 - std::min(6, static_cast<int>(score_p1.length())), '0') + score_p1;
|
||||
vides_p1 = (vides_per_jugador_[0] < 10)
|
||||
@@ -927,7 +927,7 @@ std::string EscenaJoc::construir_marcador() const {
|
||||
// Puntuació P2 (6 dígits) - mostrar zeros si inactiu
|
||||
std::string score_p2;
|
||||
std::string vides_p2;
|
||||
if (config_partida_.jugador2_actiu) {
|
||||
if (match_config_.jugador2_actiu) {
|
||||
score_p2 = std::to_string(puntuacio_per_jugador_[1]);
|
||||
score_p2 = std::string(6 - std::min(6, static_cast<int>(score_p2.length())), '0') + score_p2;
|
||||
vides_p2 = (vides_per_jugador_[1] < 10)
|
||||
@@ -943,7 +943,7 @@ std::string EscenaJoc::construir_marcador() const {
|
||||
return score_p1 + " " + vides_p1 + " LEVEL " + stage_str + " " + score_p2 + " " + vides_p2;
|
||||
}
|
||||
|
||||
void EscenaJoc::detectar_col·lisions_bales_enemics() {
|
||||
void GameScene::detectar_col·lisions_bales_enemics() {
|
||||
// Amplificador per hitbox més generós (115%)
|
||||
constexpr float AMPLIFIER = Defaults::Game::COLLISION_BULLET_ENEMY_AMPLIFIER;
|
||||
|
||||
@@ -1007,7 +1007,7 @@ void EscenaJoc::detectar_col·lisions_bales_enemics() {
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaJoc::detectar_col·lisio_naus_enemics() {
|
||||
void GameScene::detectar_col·lisio_naus_enemics() {
|
||||
// Amplificador per hitbox generós (80%)
|
||||
constexpr float AMPLIFIER = Defaults::Game::COLLISION_SHIP_ENEMY_AMPLIFIER;
|
||||
|
||||
@@ -1040,7 +1040,7 @@ void EscenaJoc::detectar_col·lisio_naus_enemics() {
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaJoc::detectar_col·lisions_bales_jugadors() {
|
||||
void GameScene::detectar_col·lisions_bales_jugadors() {
|
||||
// Skip if friendly fire disabled
|
||||
if (!Defaults::Game::FRIENDLY_FIRE_ENABLED) {
|
||||
return;
|
||||
@@ -1076,8 +1076,8 @@ void EscenaJoc::detectar_col·lisions_bales_jugadors() {
|
||||
}
|
||||
|
||||
// Skip inactive players
|
||||
bool jugador_actiu = (player_id == 0) ? config_partida_.jugador1_actiu
|
||||
: config_partida_.jugador2_actiu;
|
||||
bool jugador_actiu = (player_id == 0) ? match_config_.jugador1_actiu
|
||||
: match_config_.jugador2_actiu;
|
||||
if (!jugador_actiu) {
|
||||
continue;
|
||||
}
|
||||
@@ -1113,7 +1113,7 @@ void EscenaJoc::detectar_col·lisions_bales_jugadors() {
|
||||
|
||||
// [NEW] Stage system helper methods
|
||||
|
||||
void EscenaJoc::dibuixar_missatge_stage(const std::string& missatge) {
|
||||
void GameScene::dibuixar_missatge_stage(const std::string& missatge) {
|
||||
constexpr float escala_base = 1.0F;
|
||||
constexpr float spacing = 2.0F;
|
||||
|
||||
@@ -1182,11 +1182,11 @@ void EscenaJoc::dibuixar_missatge_stage(const std::string& missatge) {
|
||||
// Helper methods for 2-player support
|
||||
// ========================================
|
||||
|
||||
Vec2 EscenaJoc::obtenir_punt_spawn(uint8_t player_id) const {
|
||||
Vec2 GameScene::obtenir_punt_spawn(uint8_t player_id) const {
|
||||
const SDL_FRect& zona = Defaults::Zones::PLAYAREA;
|
||||
|
||||
float x_ratio;
|
||||
if (config_partida_.es_un_jugador()) {
|
||||
if (match_config_.es_un_jugador()) {
|
||||
// Un sol jugador: spawn al centre (50%)
|
||||
x_ratio = 0.5F;
|
||||
} else {
|
||||
@@ -1201,7 +1201,7 @@ Vec2 EscenaJoc::obtenir_punt_spawn(uint8_t player_id) const {
|
||||
.y = zona.y + (zona.h * Defaults::Game::SPAWN_Y_RATIO)};
|
||||
}
|
||||
|
||||
void EscenaJoc::disparar_bala(uint8_t player_id) {
|
||||
void GameScene::disparar_bala(uint8_t player_id) {
|
||||
// Verificar que el jugador está vivo
|
||||
if (itocado_per_jugador_[player_id] > 0.0F) {
|
||||
return;
|
||||
@@ -1234,14 +1234,14 @@ void EscenaJoc::disparar_bala(uint8_t player_id) {
|
||||
|
||||
// ==================== CONTINUE & JOIN SYSTEM ====================
|
||||
|
||||
void EscenaJoc::check_and_apply_continue_timeout() {
|
||||
void GameScene::check_and_apply_continue_timeout() {
|
||||
if (continue_counter_ < 0) {
|
||||
estat_game_over_ = EstatGameOver::GAME_OVER;
|
||||
estat_game_over_ = GameOverState::GAME_OVER;
|
||||
game_over_timer_ = Defaults::Game::GAME_OVER_DURATION;
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaJoc::actualitzar_continue(float delta_time) {
|
||||
void GameScene::actualitzar_continue(float delta_time) {
|
||||
continue_tick_timer_ -= delta_time;
|
||||
|
||||
if (continue_tick_timer_ <= 0.0F) {
|
||||
@@ -1252,13 +1252,13 @@ void EscenaJoc::actualitzar_continue(float delta_time) {
|
||||
check_and_apply_continue_timeout();
|
||||
|
||||
// Play sound only if still in CONTINUE state (not transitioned to GAME_OVER)
|
||||
if (estat_game_over_ == EstatGameOver::CONTINUE) {
|
||||
if (estat_game_over_ == GameOverState::CONTINUE) {
|
||||
Audio::get()->playSound(Defaults::Sound::CONTINUE, Audio::Group::GAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaJoc::processar_input_continue() {
|
||||
void GameScene::processar_input_continue() {
|
||||
auto* input = Input::get();
|
||||
|
||||
// Check START for both players
|
||||
@@ -1269,7 +1269,7 @@ void EscenaJoc::processar_input_continue() {
|
||||
// Check continue limit (skip if infinite continues)
|
||||
if (!Defaults::Game::INFINITE_CONTINUES && continues_usados_ >= Defaults::Game::MAX_CONTINUES) {
|
||||
// Max continues reached → final game over
|
||||
estat_game_over_ = EstatGameOver::GAME_OVER;
|
||||
estat_game_over_ = GameOverState::GAME_OVER;
|
||||
game_over_timer_ = Defaults::Game::GAME_OVER_DURATION;
|
||||
return;
|
||||
}
|
||||
@@ -1289,9 +1289,9 @@ void EscenaJoc::processar_input_continue() {
|
||||
|
||||
// Activate player if not already
|
||||
if (player_to_revive == 0) {
|
||||
config_partida_.jugador1_actiu = true;
|
||||
match_config_.jugador1_actiu = true;
|
||||
} else {
|
||||
config_partida_.jugador2_actiu = true;
|
||||
match_config_.jugador2_actiu = true;
|
||||
}
|
||||
|
||||
// Spawn with invulnerability
|
||||
@@ -1304,13 +1304,13 @@ void EscenaJoc::processar_input_continue() {
|
||||
puntuacio_per_jugador_[other_player] = 0;
|
||||
vides_per_jugador_[other_player] = Defaults::Game::STARTING_LIVES;
|
||||
itocado_per_jugador_[other_player] = 0.0F;
|
||||
config_partida_.jugador2_actiu = true;
|
||||
match_config_.jugador2_actiu = true;
|
||||
Vec2 spawn_pos2 = obtenir_punt_spawn(other_player);
|
||||
naus_[other_player].init(&spawn_pos2, true);
|
||||
}
|
||||
|
||||
// Resume game
|
||||
estat_game_over_ = EstatGameOver::NONE;
|
||||
estat_game_over_ = GameOverState::NONE;
|
||||
continue_counter_ = 0;
|
||||
continue_tick_timer_ = 0.0F;
|
||||
|
||||
@@ -1333,7 +1333,7 @@ void EscenaJoc::processar_input_continue() {
|
||||
check_and_apply_continue_timeout();
|
||||
|
||||
// Play sound only if still in CONTINUE state
|
||||
if (estat_game_over_ == EstatGameOver::CONTINUE) {
|
||||
if (estat_game_over_ == GameOverState::CONTINUE) {
|
||||
Audio::get()->playSound(Defaults::Sound::CONTINUE, Audio::Group::GAME);
|
||||
}
|
||||
|
||||
@@ -1342,7 +1342,7 @@ void EscenaJoc::processar_input_continue() {
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaJoc::dibuixar_continue() {
|
||||
void GameScene::dibuixar_continue() {
|
||||
const SDL_FRect& play_area = Defaults::Zones::PLAYAREA;
|
||||
constexpr float spacing = 4.0F;
|
||||
|
||||
@@ -1377,12 +1377,12 @@ void EscenaJoc::dibuixar_continue() {
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaJoc::unir_jugador(uint8_t player_id) {
|
||||
void GameScene::unir_jugador(uint8_t player_id) {
|
||||
// Activate player
|
||||
if (player_id == 0) {
|
||||
config_partida_.jugador1_actiu = true;
|
||||
match_config_.jugador1_actiu = true;
|
||||
} else {
|
||||
config_partida_.jugador2_actiu = true;
|
||||
match_config_.jugador2_actiu = true;
|
||||
}
|
||||
|
||||
// Reset stats
|
||||
@@ -1396,5 +1396,5 @@ void EscenaJoc::unir_jugador(uint8_t player_id) {
|
||||
|
||||
// No visual message, just spawn (per user requirement)
|
||||
|
||||
std::cout << "[EscenaJoc] Jugador " << (int)(player_id + 1) << " s'ha unit a la partida!" << '\n';
|
||||
std::cout << "[GameScene] Jugador " << (int)(player_id + 1) << " s'ha unit a la partida!" << '\n';
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "core/graphics/vector_text.hpp"
|
||||
#include "core/rendering/sdl_manager.hpp"
|
||||
#include "core/system/context_escenes.hpp"
|
||||
#include "core/system/scene_context.hpp"
|
||||
#include "core/system/game_config.hpp"
|
||||
#include "core/types.hpp"
|
||||
#include "game/constants.hpp"
|
||||
@@ -25,27 +25,27 @@
|
||||
#include "game/stage_system/stage_manager.hpp"
|
||||
|
||||
// Game over state machine
|
||||
enum class EstatGameOver {
|
||||
enum class GameOverState {
|
||||
NONE, // Normal gameplay
|
||||
CONTINUE, // Continue countdown screen (9→0)
|
||||
GAME_OVER // Final game over (returning to title)
|
||||
};
|
||||
|
||||
// Classe principal del joc (escena)
|
||||
class EscenaJoc {
|
||||
class GameScene {
|
||||
public:
|
||||
explicit EscenaJoc(SDLManager& sdl, GestorEscenes::ContextEscenes& context);
|
||||
~EscenaJoc() = default;
|
||||
explicit GameScene(SDLManager& sdl, SceneManager::SceneContext& context);
|
||||
~GameScene() = default;
|
||||
|
||||
void executar(); // Bucle principal de l'escena
|
||||
void run(); // Bucle principal de l'escena
|
||||
void init();
|
||||
void update(float delta_time);
|
||||
void draw();
|
||||
|
||||
private:
|
||||
SDLManager& sdl_;
|
||||
GestorEscenes::ContextEscenes& context_;
|
||||
GameConfig::ConfigPartida config_partida_; // Configuració de jugadors actius
|
||||
SceneManager::SceneContext& context_;
|
||||
GameConfig::MatchConfig match_config_; // Configuració de jugadors actius
|
||||
|
||||
// Efectes visuals
|
||||
Effects::DebrisManager debris_manager_;
|
||||
@@ -59,7 +59,7 @@ class EscenaJoc {
|
||||
|
||||
// Lives and game over system
|
||||
std::array<int, 2> vides_per_jugador_; // [0]=P1, [1]=P2
|
||||
EstatGameOver estat_game_over_; // Game over state machine (NONE, CONTINUE, GAME_OVER)
|
||||
GameOverState estat_game_over_; // Game over state machine (NONE, CONTINUE, GAME_OVER)
|
||||
int continue_counter_; // Continue countdown (9→0)
|
||||
float continue_tick_timer_; // Timer for countdown tick (1.0s)
|
||||
int continues_usados_; // Continues used this game (0-3 max)
|
||||
@@ -1,7 +1,7 @@
|
||||
// escena_logo.cpp - Implementació de l'escena logo
|
||||
// © 2025 Port a C++20
|
||||
|
||||
#include "escena_logo.hpp"
|
||||
#include "logo_scene.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cfloat>
|
||||
@@ -14,13 +14,13 @@
|
||||
#include "core/input/input.hpp"
|
||||
#include "core/input/mouse.hpp"
|
||||
#include "core/rendering/shape_renderer.hpp"
|
||||
#include "core/system/context_escenes.hpp"
|
||||
#include "core/system/scene_context.hpp"
|
||||
#include "core/system/global_events.hpp"
|
||||
|
||||
// Using declarations per simplificar el codi
|
||||
using GestorEscenes::ContextEscenes;
|
||||
using Escena = ContextEscenes::Escena;
|
||||
using Opcio = ContextEscenes::Opcio;
|
||||
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)
|
||||
@@ -45,35 +45,35 @@ static float calcular_progress_letra(size_t letra_index, size_t num_letras, floa
|
||||
return (global_progress - start) / (end - start);
|
||||
}
|
||||
|
||||
EscenaLogo::EscenaLogo(SDLManager& sdl, ContextEscenes& context)
|
||||
LogoScene::LogoScene(SDLManager& sdl, SceneContext& context)
|
||||
: sdl_(sdl),
|
||||
context_(context),
|
||||
estat_actual_(EstatAnimacio::PRE_ANIMATION),
|
||||
estat_actual_(AnimationState::PRE_ANIMATION),
|
||||
temps_estat_actual_(0.0F),
|
||||
debris_manager_(std::make_unique<Effects::DebrisManager>(sdl.obte_renderer())),
|
||||
lletra_explosio_index_(0),
|
||||
temps_des_ultima_explosio_(0.0F) {
|
||||
std::cout << "Escena Logo: Inicialitzant...\n";
|
||||
std::cout << "SceneType Logo: Inicialitzant...\n";
|
||||
|
||||
// Consumir opcions (LOGO no processa opcions actualment)
|
||||
auto opcio = context_.consumir_opcio();
|
||||
(void)opcio; // Suprimir warning
|
||||
auto option = context_.consumeOption();
|
||||
(void)option; // Suprimir warning
|
||||
|
||||
so_reproduit_.fill(false); // Inicialitzar seguiment de sons
|
||||
inicialitzar_lletres();
|
||||
}
|
||||
|
||||
EscenaLogo::~EscenaLogo() {
|
||||
LogoScene::~LogoScene() {
|
||||
// Aturar tots els sons i la música
|
||||
Audio::get()->stopAllSounds();
|
||||
std::cout << "Escena Logo: Sons aturats\n";
|
||||
std::cout << "SceneType Logo: Sons aturats\n";
|
||||
}
|
||||
|
||||
void EscenaLogo::executar() {
|
||||
void LogoScene::run() {
|
||||
SDL_Event event;
|
||||
Uint64 last_time = SDL_GetTicks();
|
||||
|
||||
while (GestorEscenes::actual == Escena::LOGO) {
|
||||
while (SceneManager::actual == SceneType::LOGO) {
|
||||
// Calcular delta_time real
|
||||
Uint64 current_time = SDL_GetTicks();
|
||||
float delta_time = (current_time - last_time) / 1000.0F;
|
||||
@@ -120,10 +120,10 @@ void EscenaLogo::executar() {
|
||||
draw();
|
||||
}
|
||||
|
||||
std::cout << "Escena Logo: Finalitzant...\n";
|
||||
std::cout << "SceneType Logo: Finalitzant...\n";
|
||||
}
|
||||
|
||||
void EscenaLogo::inicialitzar_lletres() {
|
||||
void LogoScene::inicialitzar_lletres() {
|
||||
using namespace Graphics;
|
||||
|
||||
// Llista de fitxers .shp (A repetida per a les dues A's)
|
||||
@@ -144,7 +144,7 @@ void EscenaLogo::inicialitzar_lletres() {
|
||||
for (const auto& fitxer : fitxers) {
|
||||
auto forma = ShapeLoader::load(fitxer);
|
||||
if (!forma || !forma->es_valida()) {
|
||||
std::cerr << "[EscenaLogo] Error carregant " << fitxer << '\n';
|
||||
std::cerr << "[LogoScene] Error carregant " << fitxer << '\n';
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -198,16 +198,16 @@ void EscenaLogo::inicialitzar_lletres() {
|
||||
x_actual += lletra.ancho + ESPAI_ENTRE_LLETRES;
|
||||
}
|
||||
|
||||
std::cout << "[EscenaLogo] " << lletres_.size()
|
||||
std::cout << "[LogoScene] " << lletres_.size()
|
||||
<< " lletres carregades, ancho total: " << ancho_total << " px\n";
|
||||
}
|
||||
|
||||
void EscenaLogo::canviar_estat(EstatAnimacio nou_estat) {
|
||||
void LogoScene::canviar_estat(AnimationState nou_estat) {
|
||||
estat_actual_ = nou_estat;
|
||||
temps_estat_actual_ = 0.0F; // Reset temps
|
||||
|
||||
// Inicialitzar estat d'explosió
|
||||
if (nou_estat == EstatAnimacio::EXPLOSION) {
|
||||
if (nou_estat == AnimationState::EXPLOSION) {
|
||||
lletra_explosio_index_ = 0;
|
||||
temps_des_ultima_explosio_ = 0.0F;
|
||||
|
||||
@@ -219,20 +219,20 @@ void EscenaLogo::canviar_estat(EstatAnimacio nou_estat) {
|
||||
std::random_device rd;
|
||||
std::mt19937 g(rd());
|
||||
std::shuffle(ordre_explosio_.begin(), ordre_explosio_.end(), g);
|
||||
} else if (nou_estat == EstatAnimacio::POST_EXPLOSION) {
|
||||
} else if (nou_estat == AnimationState::POST_EXPLOSION) {
|
||||
Audio::get()->playMusic("title.ogg");
|
||||
}
|
||||
|
||||
std::cout << "[EscenaLogo] Canvi a estat: " << static_cast<int>(nou_estat)
|
||||
std::cout << "[LogoScene] Canvi a estat: " << static_cast<int>(nou_estat)
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
bool EscenaLogo::totes_lletres_completes() const {
|
||||
bool LogoScene::totes_lletres_completes() const {
|
||||
// Quan global_progress = 1.0, totes les lletres tenen letra_progress = 1.0
|
||||
return temps_estat_actual_ >= DURACIO_ZOOM;
|
||||
}
|
||||
|
||||
void EscenaLogo::actualitzar_explosions(float delta_time) {
|
||||
void LogoScene::actualitzar_explosions(float delta_time) {
|
||||
temps_des_ultima_explosio_ += delta_time;
|
||||
|
||||
// Comprovar si és el moment d'explotar la següent lletra
|
||||
@@ -252,29 +252,29 @@ void EscenaLogo::actualitzar_explosions(float delta_time) {
|
||||
{.x = 0.0F, .y = 0.0F} // Sense velocitat (per defecte)
|
||||
);
|
||||
|
||||
std::cout << "[EscenaLogo] Explota lletra " << lletra_explosio_index_ << "\n";
|
||||
std::cout << "[LogoScene] Explota lletra " << lletra_explosio_index_ << "\n";
|
||||
|
||||
// Passar a la següent lletra
|
||||
lletra_explosio_index_++;
|
||||
temps_des_ultima_explosio_ = 0.0F;
|
||||
} else {
|
||||
// Totes les lletres han explotat, transició a POST_EXPLOSION
|
||||
canviar_estat(EstatAnimacio::POST_EXPLOSION);
|
||||
canviar_estat(AnimationState::POST_EXPLOSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaLogo::update(float delta_time) {
|
||||
void LogoScene::update(float delta_time) {
|
||||
temps_estat_actual_ += delta_time;
|
||||
|
||||
switch (estat_actual_) {
|
||||
case EstatAnimacio::PRE_ANIMATION:
|
||||
case AnimationState::PRE_ANIMATION:
|
||||
if (temps_estat_actual_ >= DURACIO_PRE) {
|
||||
canviar_estat(EstatAnimacio::ANIMATION);
|
||||
canviar_estat(AnimationState::ANIMATION);
|
||||
}
|
||||
break;
|
||||
|
||||
case EstatAnimacio::ANIMATION: {
|
||||
case AnimationState::ANIMATION: {
|
||||
// Reproduir so per cada lletra quan comença a aparèixer
|
||||
float global_progress = std::min(temps_estat_actual_ / DURACIO_ZOOM, 1.0F);
|
||||
|
||||
@@ -295,55 +295,55 @@ void EscenaLogo::update(float delta_time) {
|
||||
}
|
||||
|
||||
if (totes_lletres_completes()) {
|
||||
canviar_estat(EstatAnimacio::POST_ANIMATION);
|
||||
canviar_estat(AnimationState::POST_ANIMATION);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EstatAnimacio::POST_ANIMATION:
|
||||
case AnimationState::POST_ANIMATION:
|
||||
if (temps_estat_actual_ >= DURACIO_POST_ANIMATION) {
|
||||
canviar_estat(EstatAnimacio::EXPLOSION);
|
||||
canviar_estat(AnimationState::EXPLOSION);
|
||||
}
|
||||
break;
|
||||
|
||||
case EstatAnimacio::EXPLOSION:
|
||||
case AnimationState::EXPLOSION:
|
||||
actualitzar_explosions(delta_time);
|
||||
break;
|
||||
|
||||
case EstatAnimacio::POST_EXPLOSION:
|
||||
case AnimationState::POST_EXPLOSION:
|
||||
if (temps_estat_actual_ >= DURACIO_POST_EXPLOSION) {
|
||||
// Transició a pantalla de títol
|
||||
context_.canviar_escena(Escena::TITOL);
|
||||
GestorEscenes::actual = Escena::TITOL;
|
||||
context_.setNextScene(SceneType::TITLE);
|
||||
SceneManager::actual = SceneType::TITLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Verificar botones de skip (SHOOT P1/P2)
|
||||
if (checkSkipButtonPressed()) {
|
||||
context_.canviar_escena(Escena::TITOL, Opcio::JUMP_TO_TITLE_MAIN);
|
||||
GestorEscenes::actual = Escena::TITOL;
|
||||
context_.setNextScene(SceneType::TITLE, Option::JUMP_TO_TITLE_MAIN);
|
||||
SceneManager::actual = SceneType::TITLE;
|
||||
}
|
||||
|
||||
// Actualitzar animacions de debris
|
||||
debris_manager_->update(delta_time);
|
||||
}
|
||||
|
||||
void EscenaLogo::draw() {
|
||||
void LogoScene::draw() {
|
||||
// Fons negre
|
||||
sdl_.neteja(0, 0, 0);
|
||||
|
||||
// PRE_ANIMATION: Només pantalla negra
|
||||
if (estat_actual_ == EstatAnimacio::PRE_ANIMATION) {
|
||||
if (estat_actual_ == AnimationState::PRE_ANIMATION) {
|
||||
sdl_.presenta();
|
||||
return; // No renderitzar lletres
|
||||
}
|
||||
|
||||
// ANIMATION o POST_ANIMATION: Dibuixar lletres amb animació
|
||||
if (estat_actual_ == EstatAnimacio::ANIMATION ||
|
||||
estat_actual_ == EstatAnimacio::POST_ANIMATION) {
|
||||
if (estat_actual_ == AnimationState::ANIMATION ||
|
||||
estat_actual_ == AnimationState::POST_ANIMATION) {
|
||||
float global_progress =
|
||||
(estat_actual_ == EstatAnimacio::ANIMATION)
|
||||
(estat_actual_ == AnimationState::ANIMATION)
|
||||
? std::min(temps_estat_actual_ / DURACIO_ZOOM, 1.0F)
|
||||
: 1.0F; // POST: mantenir al 100%
|
||||
|
||||
@@ -384,7 +384,7 @@ void EscenaLogo::draw() {
|
||||
}
|
||||
|
||||
// EXPLOSION: Dibuixar només lletres que encara no han explotat
|
||||
if (estat_actual_ == EstatAnimacio::EXPLOSION) {
|
||||
if (estat_actual_ == AnimationState::EXPLOSION) {
|
||||
// Crear conjunt de lletres ja explotades
|
||||
std::set<size_t> explotades;
|
||||
for (size_t i = 0; i < lletra_explosio_index_; i++) {
|
||||
@@ -415,10 +415,10 @@ void EscenaLogo::draw() {
|
||||
sdl_.presenta();
|
||||
}
|
||||
|
||||
auto EscenaLogo::checkSkipButtonPressed() -> bool {
|
||||
auto LogoScene::checkSkipButtonPressed() -> bool {
|
||||
return Input::get()->checkAnyPlayerAction(ARCADE_BUTTONS);
|
||||
}
|
||||
|
||||
void EscenaLogo::processar_events(const SDL_Event& event) {
|
||||
void LogoScene::processar_events(const SDL_Event& event) {
|
||||
// No procesar eventos genéricos aquí - la lógica se movió a update()
|
||||
}
|
||||
@@ -14,19 +14,19 @@
|
||||
#include "core/graphics/shape.hpp"
|
||||
#include "core/input/input_types.hpp"
|
||||
#include "core/rendering/sdl_manager.hpp"
|
||||
#include "core/system/context_escenes.hpp"
|
||||
#include "core/system/scene_context.hpp"
|
||||
#include "core/types.hpp"
|
||||
#include "game/effects/debris_manager.hpp"
|
||||
|
||||
class EscenaLogo {
|
||||
class LogoScene {
|
||||
public:
|
||||
explicit EscenaLogo(SDLManager& sdl, GestorEscenes::ContextEscenes& context);
|
||||
~EscenaLogo(); // Destructor per aturar sons
|
||||
void executar(); // Bucle principal de l'escena
|
||||
explicit LogoScene(SDLManager& sdl, SceneManager::SceneContext& context);
|
||||
~LogoScene(); // Destructor per aturar sons
|
||||
void run(); // Bucle principal de l'escena
|
||||
|
||||
private:
|
||||
// Màquina d'estats per l'animació
|
||||
enum class EstatAnimacio {
|
||||
enum class AnimationState {
|
||||
PRE_ANIMATION, // Pantalla negra inicial
|
||||
ANIMATION, // Animació de zoom de lletres
|
||||
POST_ANIMATION, // Logo complet visible
|
||||
@@ -35,8 +35,8 @@ class EscenaLogo {
|
||||
};
|
||||
|
||||
SDLManager& sdl_;
|
||||
GestorEscenes::ContextEscenes& context_;
|
||||
EstatAnimacio estat_actual_; // Estat actual de la màquina
|
||||
SceneManager::SceneContext& context_;
|
||||
AnimationState estat_actual_; // Estat actual de la màquina
|
||||
float
|
||||
temps_estat_actual_; // Temps en l'estat actual (reset en cada transició)
|
||||
|
||||
@@ -86,6 +86,6 @@ class EscenaLogo {
|
||||
auto checkSkipButtonPressed() -> bool;
|
||||
|
||||
// Mètodes de gestió d'estats
|
||||
void canviar_estat(EstatAnimacio nou_estat);
|
||||
void canviar_estat(AnimationState nou_estat);
|
||||
[[nodiscard]] bool totes_lletres_completes() const;
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
// escena_titol.cpp - Implementació de l'escena de títol
|
||||
// © 2025 Port a C++20
|
||||
|
||||
#include "escena_titol.hpp"
|
||||
#include "title_scene.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cfloat>
|
||||
@@ -15,38 +15,38 @@
|
||||
#include "core/input/input.hpp"
|
||||
#include "core/input/mouse.hpp"
|
||||
#include "core/rendering/shape_renderer.hpp"
|
||||
#include "core/system/context_escenes.hpp"
|
||||
#include "core/system/scene_context.hpp"
|
||||
#include "core/system/global_events.hpp"
|
||||
#include "project.h"
|
||||
|
||||
// Using declarations per simplificar el codi
|
||||
using GestorEscenes::ContextEscenes;
|
||||
using Escena = ContextEscenes::Escena;
|
||||
using Opcio = ContextEscenes::Opcio;
|
||||
using SceneManager::SceneContext;
|
||||
using SceneType = SceneContext::SceneType;
|
||||
using Option = SceneContext::Option;
|
||||
|
||||
EscenaTitol::EscenaTitol(SDLManager& sdl, ContextEscenes& context)
|
||||
TitleScene::TitleScene(SDLManager& sdl, SceneContext& context)
|
||||
: sdl_(sdl),
|
||||
context_(context),
|
||||
text_(sdl.obte_renderer()),
|
||||
estat_actual_(EstatTitol::STARFIELD_FADE_IN),
|
||||
estat_actual_(TitleState::STARFIELD_FADE_IN),
|
||||
temps_acumulat_(0.0F),
|
||||
temps_animacio_(0.0F),
|
||||
temps_estat_main_(0.0F),
|
||||
animacio_activa_(false),
|
||||
factor_lerp_(0.0F) {
|
||||
std::cout << "Escena Titol: Inicialitzant...\n";
|
||||
std::cout << "SceneType Titol: Inicialitzant...\n";
|
||||
|
||||
// Inicialitzar configuració de partida (cap jugador actiu per defecte)
|
||||
config_partida_.jugador1_actiu = false;
|
||||
config_partida_.jugador2_actiu = false;
|
||||
config_partida_.mode = GameConfig::Mode::NORMAL;
|
||||
match_config_.jugador1_actiu = false;
|
||||
match_config_.jugador2_actiu = false;
|
||||
match_config_.mode = GameConfig::Mode::NORMAL;
|
||||
|
||||
// Processar opció del context
|
||||
auto opcio = context_.consumir_opcio();
|
||||
auto option = context_.consumeOption();
|
||||
|
||||
if (opcio == Opcio::JUMP_TO_TITLE_MAIN) {
|
||||
std::cout << "Escena Titol: Opció JUMP_TO_TITLE_MAIN activada\n";
|
||||
estat_actual_ = EstatTitol::MAIN;
|
||||
if (option == Option::JUMP_TO_TITLE_MAIN) {
|
||||
std::cout << "SceneType Titol: Opció JUMP_TO_TITLE_MAIN activada\n";
|
||||
estat_actual_ = TitleState::MAIN;
|
||||
temps_estat_main_ = 0.0F;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ EscenaTitol::EscenaTitol(SDLManager& sdl, ContextEscenes& context)
|
||||
);
|
||||
|
||||
// Brightness depèn de l'opció
|
||||
if (estat_actual_ == EstatTitol::MAIN) {
|
||||
if (estat_actual_ == TitleState::MAIN) {
|
||||
// Si saltem a MAIN, starfield instantàniament brillant
|
||||
starfield_->set_brightness(BRIGHTNESS_STARFIELD);
|
||||
} else {
|
||||
@@ -81,7 +81,7 @@ EscenaTitol::EscenaTitol(SDLManager& sdl, ContextEscenes& context)
|
||||
ship_animator_ = std::make_unique<Title::ShipAnimator>(sdl_.obte_renderer());
|
||||
ship_animator_->init();
|
||||
|
||||
if (estat_actual_ == EstatTitol::MAIN) {
|
||||
if (estat_actual_ == TitleState::MAIN) {
|
||||
// Jump to MAIN: empezar entrada inmediatamente
|
||||
ship_animator_->set_visible(true);
|
||||
ship_animator_->start_entry_animation();
|
||||
@@ -99,12 +99,12 @@ EscenaTitol::EscenaTitol(SDLManager& sdl, ContextEscenes& context)
|
||||
}
|
||||
}
|
||||
|
||||
EscenaTitol::~EscenaTitol() {
|
||||
TitleScene::~TitleScene() {
|
||||
// Aturar música de títol quan es destrueix l'escena
|
||||
Audio::get()->stopMusic();
|
||||
}
|
||||
|
||||
void EscenaTitol::inicialitzar_titol() {
|
||||
void TitleScene::inicialitzar_titol() {
|
||||
using namespace Graphics;
|
||||
|
||||
// === LÍNIA 1: "ORNI" ===
|
||||
@@ -120,7 +120,7 @@ void EscenaTitol::inicialitzar_titol() {
|
||||
for (const auto& fitxer : fitxers_orni) {
|
||||
auto forma = ShapeLoader::load(fitxer);
|
||||
if (!forma || !forma->es_valida()) {
|
||||
std::cerr << "[EscenaTitol] Error carregant " << fitxer << '\n';
|
||||
std::cerr << "[TitleScene] Error carregant " << fitxer << '\n';
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ void EscenaTitol::inicialitzar_titol() {
|
||||
x_actual += lletra.ancho + ESPAI_ENTRE_LLETRES;
|
||||
}
|
||||
|
||||
std::cout << "[EscenaTitol] Línia 1 (ORNI): " << lletres_orni_.size()
|
||||
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!" ===
|
||||
@@ -175,7 +175,7 @@ void EscenaTitol::inicialitzar_titol() {
|
||||
float separacion_lineas = Defaults::Game::HEIGHT * Defaults::Title::Layout::LOGO_LINE_SPACING;
|
||||
y_attack_dinamica_ = y_orni + altura_orni + separacion_lineas;
|
||||
|
||||
std::cout << "[EscenaTitol] Altura ORNI: " << altura_orni
|
||||
std::cout << "[TitleScene] Altura ORNI: " << altura_orni
|
||||
<< " px, Y_ATTACK dinàmica: " << y_attack_dinamica_ << " px\n";
|
||||
|
||||
// === LÍNIA 2: "ATTACK!" ===
|
||||
@@ -194,7 +194,7 @@ void EscenaTitol::inicialitzar_titol() {
|
||||
for (const auto& fitxer : fitxers_attack) {
|
||||
auto forma = ShapeLoader::load(fitxer);
|
||||
if (!forma || !forma->es_valida()) {
|
||||
std::cerr << "[EscenaTitol] Error carregant " << fitxer << '\n';
|
||||
std::cerr << "[TitleScene] Error carregant " << fitxer << '\n';
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ void EscenaTitol::inicialitzar_titol() {
|
||||
x_actual += lletra.ancho + ESPAI_ENTRE_LLETRES;
|
||||
}
|
||||
|
||||
std::cout << "[EscenaTitol] Línia 2 (ATTACK!): " << lletres_attack_.size()
|
||||
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
|
||||
@@ -253,14 +253,14 @@ void EscenaTitol::inicialitzar_titol() {
|
||||
posicions_originals_attack_.push_back(lletra.posicio);
|
||||
}
|
||||
|
||||
std::cout << "[EscenaTitol] Animació: Posicions originals guardades\n";
|
||||
std::cout << "[TitleScene] Animació: Posicions originals guardades\n";
|
||||
}
|
||||
|
||||
void EscenaTitol::executar() {
|
||||
void TitleScene::run() {
|
||||
SDL_Event event;
|
||||
Uint64 last_time = SDL_GetTicks();
|
||||
|
||||
while (GestorEscenes::actual == Escena::TITOL) {
|
||||
while (SceneManager::actual == SceneType::TITLE) {
|
||||
// Calcular delta_time real
|
||||
Uint64 current_time = SDL_GetTicks();
|
||||
float delta_time = (current_time - last_time) / 1000.0F;
|
||||
@@ -316,10 +316,10 @@ void EscenaTitol::executar() {
|
||||
sdl_.presenta();
|
||||
}
|
||||
|
||||
std::cout << "Escena Titol: Finalitzant...\n";
|
||||
std::cout << "SceneType Titol: Finalitzant...\n";
|
||||
}
|
||||
|
||||
void EscenaTitol::update(float delta_time) {
|
||||
void TitleScene::update(float delta_time) {
|
||||
// Actualitzar starfield (sempre actiu)
|
||||
if (starfield_) {
|
||||
starfield_->update(delta_time);
|
||||
@@ -327,15 +327,15 @@ void EscenaTitol::update(float delta_time) {
|
||||
|
||||
// Actualitzar naus (quan visibles)
|
||||
if (ship_animator_ &&
|
||||
(estat_actual_ == EstatTitol::STARFIELD_FADE_IN ||
|
||||
estat_actual_ == EstatTitol::STARFIELD ||
|
||||
estat_actual_ == EstatTitol::MAIN ||
|
||||
estat_actual_ == EstatTitol::PLAYER_JOIN_PHASE)) {
|
||||
(estat_actual_ == TitleState::STARFIELD_FADE_IN ||
|
||||
estat_actual_ == TitleState::STARFIELD ||
|
||||
estat_actual_ == TitleState::MAIN ||
|
||||
estat_actual_ == TitleState::PLAYER_JOIN_PHASE)) {
|
||||
ship_animator_->update(delta_time);
|
||||
}
|
||||
|
||||
switch (estat_actual_) {
|
||||
case EstatTitol::STARFIELD_FADE_IN: {
|
||||
case TitleState::STARFIELD_FADE_IN: {
|
||||
temps_acumulat_ += delta_time;
|
||||
|
||||
// Calcular progrés del fade (0.0 → 1.0)
|
||||
@@ -347,17 +347,17 @@ void EscenaTitol::update(float delta_time) {
|
||||
|
||||
// Transició a STARFIELD quan el fade es completa
|
||||
if (temps_acumulat_ >= DURACIO_FADE_IN) {
|
||||
estat_actual_ = EstatTitol::STARFIELD;
|
||||
estat_actual_ = TitleState::STARFIELD;
|
||||
temps_acumulat_ = 0.0F; // Reset timer per al següent estat
|
||||
starfield_->set_brightness(BRIGHTNESS_STARFIELD); // Assegurar valor final
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EstatTitol::STARFIELD:
|
||||
case TitleState::STARFIELD:
|
||||
temps_acumulat_ += delta_time;
|
||||
if (temps_acumulat_ >= DURACIO_INIT) {
|
||||
estat_actual_ = EstatTitol::MAIN;
|
||||
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
|
||||
@@ -366,7 +366,7 @@ void EscenaTitol::update(float delta_time) {
|
||||
}
|
||||
break;
|
||||
|
||||
case EstatTitol::MAIN: {
|
||||
case TitleState::MAIN: {
|
||||
temps_estat_main_ += delta_time;
|
||||
|
||||
// Iniciar animació d'entrada de naus després del delay
|
||||
@@ -399,7 +399,7 @@ void EscenaTitol::update(float delta_time) {
|
||||
break;
|
||||
}
|
||||
|
||||
case EstatTitol::PLAYER_JOIN_PHASE:
|
||||
case TitleState::PLAYER_JOIN_PHASE:
|
||||
temps_acumulat_ += delta_time;
|
||||
|
||||
// Continuar animació orbital durant la transició
|
||||
@@ -407,22 +407,22 @@ void EscenaTitol::update(float delta_time) {
|
||||
|
||||
// [NOU] Continuar comprovant si l'altre jugador vol unir-se durant la transició ("late join")
|
||||
{
|
||||
bool p1_actiu_abans = config_partida_.jugador1_actiu;
|
||||
bool p2_actiu_abans = config_partida_.jugador2_actiu;
|
||||
bool p1_actiu_abans = match_config_.jugador1_actiu;
|
||||
bool p2_actiu_abans = match_config_.jugador2_actiu;
|
||||
|
||||
if (checkStartGameButtonPressed()) {
|
||||
// Updates config_partida_ if pressed, logs are in the method
|
||||
context_.set_config_partida(config_partida_);
|
||||
// Updates match_config_ if pressed, logs are in the method
|
||||
context_.setMatchConfig(match_config_);
|
||||
|
||||
// Trigger animació de sortida per la nau que acaba d'unir-se
|
||||
if (ship_animator_) {
|
||||
if (config_partida_.jugador1_actiu && !p1_actiu_abans) {
|
||||
if (match_config_.jugador1_actiu && !p1_actiu_abans) {
|
||||
ship_animator_->trigger_exit_animation_for_player(1);
|
||||
std::cout << "[EscenaTitol] P1 late join - ship exiting\n";
|
||||
std::cout << "[TitleScene] P1 late join - ship exiting\n";
|
||||
}
|
||||
if (config_partida_.jugador2_actiu && !p2_actiu_abans) {
|
||||
if (match_config_.jugador2_actiu && !p2_actiu_abans) {
|
||||
ship_animator_->trigger_exit_animation_for_player(2);
|
||||
std::cout << "[EscenaTitol] P2 late join - ship exiting\n";
|
||||
std::cout << "[TitleScene] P2 late join - ship exiting\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,35 +432,35 @@ void EscenaTitol::update(float delta_time) {
|
||||
// Reiniciar el timer per allargar el temps de transició
|
||||
temps_acumulat_ = 0.0F;
|
||||
|
||||
std::cout << "[EscenaTitol] Segon jugador s'ha unit - so i timer reiniciats\n";
|
||||
std::cout << "[TitleScene] Segon jugador s'ha unit - so i timer reiniciats\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (temps_acumulat_ >= DURACIO_TRANSITION) {
|
||||
// Transició a pantalla negra
|
||||
estat_actual_ = EstatTitol::BLACK_SCREEN;
|
||||
estat_actual_ = TitleState::BLACK_SCREEN;
|
||||
temps_acumulat_ = 0.0F;
|
||||
std::cout << "[EscenaTitol] Passant a BLACK_SCREEN\n";
|
||||
std::cout << "[TitleScene] Passant a BLACK_SCREEN\n";
|
||||
}
|
||||
break;
|
||||
|
||||
case EstatTitol::BLACK_SCREEN:
|
||||
case TitleState::BLACK_SCREEN:
|
||||
temps_acumulat_ += delta_time;
|
||||
|
||||
// No animation, no input checking - just wait
|
||||
if (temps_acumulat_ >= DURACIO_BLACK_SCREEN) {
|
||||
// Transició a escena JOC
|
||||
GestorEscenes::actual = Escena::JOC;
|
||||
std::cout << "[EscenaTitol] Canviant a escena JOC\n";
|
||||
// Transició a escena GAME
|
||||
SceneManager::actual = SceneType::GAME;
|
||||
std::cout << "[TitleScene] Canviant a escena GAME\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Verificar botones de skip (FIRE/THRUST/START) para saltar escenas ANTES de MAIN
|
||||
if (estat_actual_ == EstatTitol::STARFIELD_FADE_IN || estat_actual_ == EstatTitol::STARFIELD) {
|
||||
if (estat_actual_ == TitleState::STARFIELD_FADE_IN || estat_actual_ == TitleState::STARFIELD) {
|
||||
if (checkSkipButtonPressed()) {
|
||||
// Saltar a MAIN
|
||||
estat_actual_ = EstatTitol::MAIN;
|
||||
estat_actual_ = TitleState::MAIN;
|
||||
starfield_->set_brightness(BRIGHTNESS_STARFIELD);
|
||||
temps_estat_main_ = 0.0F;
|
||||
|
||||
@@ -469,10 +469,10 @@ void EscenaTitol::update(float delta_time) {
|
||||
}
|
||||
|
||||
// Verificar boton START para iniciar partida desde MAIN
|
||||
if (estat_actual_ == EstatTitol::MAIN) {
|
||||
if (estat_actual_ == TitleState::MAIN) {
|
||||
// Guardar estat anterior per detectar qui ha premut START AQUEST frame
|
||||
bool p1_actiu_abans = config_partida_.jugador1_actiu;
|
||||
bool p2_actiu_abans = config_partida_.jugador2_actiu;
|
||||
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
|
||||
@@ -482,26 +482,26 @@ void EscenaTitol::update(float delta_time) {
|
||||
}
|
||||
|
||||
// Configurar partida abans de canviar d'escena
|
||||
context_.set_config_partida(config_partida_);
|
||||
std::cout << "[EscenaTitol] Configuració de partida - P1: "
|
||||
<< (config_partida_.jugador1_actiu ? "ACTIU" : "INACTIU")
|
||||
context_.setMatchConfig(match_config_);
|
||||
std::cout << "[TitleScene] Configuració de partida - P1: "
|
||||
<< (match_config_.jugador1_actiu ? "ACTIU" : "INACTIU")
|
||||
<< ", P2: "
|
||||
<< (config_partida_.jugador2_actiu ? "ACTIU" : "INACTIU")
|
||||
<< (match_config_.jugador2_actiu ? "ACTIU" : "INACTIU")
|
||||
<< '\n';
|
||||
|
||||
context_.canviar_escena(Escena::JOC);
|
||||
estat_actual_ = EstatTitol::PLAYER_JOIN_PHASE;
|
||||
context_.setNextScene(SceneType::GAME);
|
||||
estat_actual_ = TitleState::PLAYER_JOIN_PHASE;
|
||||
temps_acumulat_ = 0.0F;
|
||||
|
||||
// Trigger animació de sortida NOMÉS per les naus que han premut START
|
||||
if (ship_animator_) {
|
||||
if (config_partida_.jugador1_actiu && !p1_actiu_abans) {
|
||||
if (match_config_.jugador1_actiu && !p1_actiu_abans) {
|
||||
ship_animator_->trigger_exit_animation_for_player(1);
|
||||
std::cout << "[EscenaTitol] P1 ship exiting\n";
|
||||
std::cout << "[TitleScene] P1 ship exiting\n";
|
||||
}
|
||||
if (config_partida_.jugador2_actiu && !p2_actiu_abans) {
|
||||
if (match_config_.jugador2_actiu && !p2_actiu_abans) {
|
||||
ship_animator_->trigger_exit_animation_for_player(2);
|
||||
std::cout << "[EscenaTitol] P2 ship exiting\n";
|
||||
std::cout << "[TitleScene] P2 ship exiting\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,7 +511,7 @@ void EscenaTitol::update(float delta_time) {
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaTitol::actualitzar_animacio_logo(float delta_time) {
|
||||
void TitleScene::actualitzar_animacio_logo(float delta_time) {
|
||||
// Només calcular i aplicar offsets si l'animació està activa
|
||||
if (animacio_activa_) {
|
||||
// Acumular temps escalat
|
||||
@@ -541,29 +541,29 @@ void EscenaTitol::actualitzar_animacio_logo(float delta_time) {
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaTitol::draw() {
|
||||
void TitleScene::draw() {
|
||||
// Dibuixar starfield de fons (en tots els estats excepte BLACK_SCREEN)
|
||||
if (starfield_ && estat_actual_ != EstatTitol::BLACK_SCREEN) {
|
||||
if (starfield_ && estat_actual_ != TitleState::BLACK_SCREEN) {
|
||||
starfield_->draw();
|
||||
}
|
||||
|
||||
// Dibuixar naus (després starfield, abans logo)
|
||||
if (ship_animator_ &&
|
||||
(estat_actual_ == EstatTitol::STARFIELD_FADE_IN ||
|
||||
estat_actual_ == EstatTitol::STARFIELD ||
|
||||
estat_actual_ == EstatTitol::MAIN ||
|
||||
estat_actual_ == EstatTitol::PLAYER_JOIN_PHASE)) {
|
||||
(estat_actual_ == TitleState::STARFIELD_FADE_IN ||
|
||||
estat_actual_ == TitleState::STARFIELD ||
|
||||
estat_actual_ == TitleState::MAIN ||
|
||||
estat_actual_ == TitleState::PLAYER_JOIN_PHASE)) {
|
||||
ship_animator_->draw();
|
||||
}
|
||||
|
||||
// En els estats STARFIELD_FADE_IN i STARFIELD, només mostrar starfield (sense text)
|
||||
if (estat_actual_ == EstatTitol::STARFIELD_FADE_IN || estat_actual_ == EstatTitol::STARFIELD) {
|
||||
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)
|
||||
if (estat_actual_ == EstatTitol::MAIN || estat_actual_ == EstatTitol::PLAYER_JOIN_PHASE) {
|
||||
if (estat_actual_ == TitleState::MAIN || estat_actual_ == TitleState::PLAYER_JOIN_PHASE) {
|
||||
// === Calcular i renderitzar ombra (només si animació activa) ===
|
||||
if (animacio_activa_) {
|
||||
float temps_shadow = temps_animacio_ - SHADOW_DELAY;
|
||||
@@ -648,7 +648,7 @@ void EscenaTitol::draw() {
|
||||
const float spacing = Defaults::Title::Layout::TEXT_SPACING;
|
||||
|
||||
bool mostrar_text = true;
|
||||
if (estat_actual_ == EstatTitol::PLAYER_JOIN_PHASE) {
|
||||
if (estat_actual_ == TitleState::PLAYER_JOIN_PHASE) {
|
||||
// Parpelleig: sin oscil·la entre -1 i 1, volem ON quan > 0
|
||||
float fase = temps_acumulat_ * BLINK_FREQUENCY * 2.0F * std::numbers::pi_v<float>; // 2π × freq × temps
|
||||
mostrar_text = (std::sin(fase) > 0.0F);
|
||||
@@ -697,27 +697,27 @@ void EscenaTitol::draw() {
|
||||
}
|
||||
}
|
||||
|
||||
auto EscenaTitol::checkSkipButtonPressed() -> bool {
|
||||
auto TitleScene::checkSkipButtonPressed() -> bool {
|
||||
return Input::get()->checkAnyPlayerAction(ARCADE_BUTTONS);
|
||||
}
|
||||
|
||||
auto EscenaTitol::checkStartGameButtonPressed() -> bool {
|
||||
auto TitleScene::checkStartGameButtonPressed() -> bool {
|
||||
auto* input = Input::get();
|
||||
bool any_pressed = false;
|
||||
|
||||
for (auto action : START_GAME_BUTTONS) {
|
||||
if (input->checkActionPlayer1(action, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||
if (!config_partida_.jugador1_actiu) {
|
||||
config_partida_.jugador1_actiu = true;
|
||||
if (!match_config_.jugador1_actiu) {
|
||||
match_config_.jugador1_actiu = true;
|
||||
any_pressed = true;
|
||||
std::cout << "[EscenaTitol] P1 pressed START\n";
|
||||
std::cout << "[TitleScene] P1 pressed START\n";
|
||||
}
|
||||
}
|
||||
if (input->checkActionPlayer2(action, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||
if (!config_partida_.jugador2_actiu) {
|
||||
config_partida_.jugador2_actiu = true;
|
||||
if (!match_config_.jugador2_actiu) {
|
||||
match_config_.jugador2_actiu = true;
|
||||
any_pressed = true;
|
||||
std::cout << "[EscenaTitol] P2 pressed START\n";
|
||||
std::cout << "[TitleScene] P2 pressed START\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -725,6 +725,6 @@ auto EscenaTitol::checkStartGameButtonPressed() -> bool {
|
||||
return any_pressed;
|
||||
}
|
||||
|
||||
void EscenaTitol::processar_events(const SDL_Event& event) {
|
||||
void TitleScene::processar_events(const SDL_Event& event) {
|
||||
// No procesar eventos genéricos aquí - la lógica se movió a update()
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "core/graphics/vector_text.hpp"
|
||||
#include "core/input/input_types.hpp"
|
||||
#include "core/rendering/sdl_manager.hpp"
|
||||
#include "core/system/context_escenes.hpp"
|
||||
#include "core/system/scene_context.hpp"
|
||||
#include "core/system/game_config.hpp"
|
||||
#include "core/types.hpp"
|
||||
#include "game/title/ship_animator.hpp"
|
||||
@@ -25,15 +25,15 @@
|
||||
static constexpr std::array<InputAction, 1> START_GAME_BUTTONS = {
|
||||
InputAction::START};
|
||||
|
||||
class EscenaTitol {
|
||||
class TitleScene {
|
||||
public:
|
||||
explicit EscenaTitol(SDLManager& sdl, GestorEscenes::ContextEscenes& context);
|
||||
~EscenaTitol(); // Destructor per aturar música
|
||||
void executar(); // Bucle principal de l'escena
|
||||
explicit TitleScene(SDLManager& sdl, SceneManager::SceneContext& context);
|
||||
~TitleScene(); // Destructor per aturar música
|
||||
void run(); // Bucle principal de l'escena
|
||||
|
||||
private:
|
||||
// Màquina d'estats per la pantalla de títol
|
||||
enum class EstatTitol {
|
||||
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)
|
||||
@@ -51,12 +51,12 @@ class EscenaTitol {
|
||||
};
|
||||
|
||||
SDLManager& sdl_;
|
||||
GestorEscenes::ContextEscenes& context_;
|
||||
GameConfig::ConfigPartida config_partida_; // Configuració de jugadors actius
|
||||
SceneManager::SceneContext& context_;
|
||||
GameConfig::MatchConfig match_config_; // Configuració de jugadors actius
|
||||
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
|
||||
EstatTitol estat_actual_; // Estat actual de la màquina
|
||||
TitleState estat_actual_; // Estat actual de la màquina
|
||||
float temps_acumulat_; // Temps acumulat per l'estat INIT
|
||||
|
||||
// Lletres del títol "ORNI ATTACK!"
|
||||
@@ -129,10 +129,10 @@ 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)
|
||||
// Note: The actual enemy array update happens in EscenaJoc::update()
|
||||
// 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 EscenaJoc
|
||||
(void)pausar_spawn; // Passed to spawn_controller_.update() by GameScene
|
||||
}
|
||||
|
||||
void StageManager::processar_level_completed(float delta_time) {
|
||||
|
||||
@@ -68,7 +68,7 @@ class ShipAnimator {
|
||||
void update(float delta_time);
|
||||
void draw() const;
|
||||
|
||||
// Control d'estat (cridat per EscenaTitol)
|
||||
// Control d'estat (cridat per TitleScene)
|
||||
void start_entry_animation();
|
||||
void trigger_exit_animation(); // Anima totes les naus
|
||||
void trigger_exit_animation_for_player(int jugador_id); // Anima només una nau (P1=1, P2=2)
|
||||
|
||||
Reference in New Issue
Block a user