afegides musiques

afegit control de brillo al starfield
This commit is contained in:
2025-12-03 19:27:36 +01:00
parent 3b0354da54
commit a3aeed4b7c
11 changed files with 109 additions and 29 deletions

View File

@@ -318,7 +318,7 @@ endif
# Backup to remote server # Backup to remote server
backup: backup:
@echo "Backing up project to maverick:/home/sergio/git-backup/asteroids..." @echo "Backing up project to maverick:/home/sergio/git-backup/orni..."
rsync -a --delete \ rsync -a --delete \
--exclude='build/' \ --exclude='build/' \
--exclude='*.o' \ --exclude='*.o' \
@@ -326,7 +326,7 @@ backup:
--exclude='orni' \ --exclude='orni' \
--exclude='orni_debug' \ --exclude='orni_debug' \
--exclude='*_release/' \ --exclude='*_release/' \
$(DIR_ROOT) maverick:/home/sergio/git-backup/asteroids/ $(DIR_ROOT) maverick:/home/sergio/git-backup/orni/
@echo "Backup completed successfully" @echo "Backup completed successfully"
# Help target # Help target

BIN
data/music/game.ogg Normal file

Binary file not shown.

BIN
data/music/title.ogg Normal file

Binary file not shown.

View File

@@ -103,9 +103,12 @@ float Starfield::calcular_escala(const Estrella& estrella) const {
float Starfield::calcular_brightness(const Estrella& estrella) const { float Starfield::calcular_brightness(const Estrella& estrella) const {
// Interpolació lineal: estrelles properes (vora) més brillants // Interpolació lineal: estrelles properes (vora) més brillants
// distancia_centre: 0.0 (centre, llunyanes) → 1.0 (vora, properes) // distancia_centre: 0.0 (centre, llunyanes) → 1.0 (vora, properes)
return Defaults::Brightness::STARFIELD_MIN + float brightness_base = Defaults::Brightness::STARFIELD_MIN +
(Defaults::Brightness::STARFIELD_MAX - Defaults::Brightness::STARFIELD_MIN) * (Defaults::Brightness::STARFIELD_MAX - Defaults::Brightness::STARFIELD_MIN) *
estrella.distancia_centre; estrella.distancia_centre;
// Aplicar multiplicador i limitar a 1.0
return std::min(1.0f, brightness_base * multiplicador_brightness_);
} }
// Actualitzar posicions de les estrelles // Actualitzar posicions de les estrelles
@@ -135,6 +138,11 @@ void Starfield::actualitzar(float delta_time) {
} }
} }
// Establir multiplicador de brightness
void Starfield::set_brightness(float multiplier) {
multiplicador_brightness_ = std::max(0.0f, multiplier); // Evitar valors negatius
}
// Dibuixar totes les estrelles // Dibuixar totes les estrelles
void Starfield::dibuixar() { void Starfield::dibuixar() {
if (!shape_estrella_->es_valida()) { if (!shape_estrella_->es_valida()) {

View File

@@ -42,6 +42,7 @@ class Starfield {
// Setters per ajustar paràmetres en temps real // Setters per ajustar paràmetres en temps real
void set_punt_fuga(const Punt& punt) { punt_fuga_ = punt; } void set_punt_fuga(const Punt& punt) { punt_fuga_ = punt; }
void set_brightness(float multiplier);
private: private:
// Estructura interna per cada estrella // Estructura interna per cada estrella
@@ -75,6 +76,7 @@ class Starfield {
SDL_FRect area_; // Àrea activa SDL_FRect area_; // Àrea activa
float radi_max_; // Distància màxima del centre al límit de pantalla float radi_max_; // Distància màxima del centre al límit de pantalla
int densitat_; // Nombre total d'estrelles int densitat_; // Nombre total d'estrelles
float multiplicador_brightness_{1.0f}; // Multiplicador de brillantor (1.0 = default)
}; };
} // namespace Graphics } // namespace Graphics

View File

@@ -8,6 +8,7 @@
#include <iostream> #include <iostream>
#include "core/audio/audio.hpp" #include "core/audio/audio.hpp"
#include "core/audio/audio_cache.hpp"
#include "core/defaults.hpp" #include "core/defaults.hpp"
#include "core/rendering/sdl_manager.hpp" #include "core/rendering/sdl_manager.hpp"
#include "game/escenes/escena_joc.hpp" #include "game/escenes/escena_joc.hpp"
@@ -161,6 +162,13 @@ auto Director::run() -> int {
// Inicialitzar sistema d'audio // Inicialitzar sistema d'audio
Audio::init(); Audio::init();
// Precachejar música per evitar lag al començar
AudioCache::getMusic("title.ogg");
if (Options::console) {
std::cout << "Música precachejada: "
<< AudioCache::getMusicCacheSize() << " fitxers\n";
}
// Bucle principal de gestió d'escenes // Bucle principal de gestió d'escenes
while (GestorEscenes::actual != GestorEscenes::Escena::EIXIR) { while (GestorEscenes::actual != GestorEscenes::Escena::EIXIR) {
switch (GestorEscenes::actual) { switch (GestorEscenes::actual) {

View File

@@ -141,6 +141,9 @@ void EscenaJoc::inicialitzar() {
for (auto& bala : bales_) { for (auto& bala : bales_) {
bala.inicialitzar(); bala.inicialitzar();
} }
// Iniciar música de joc (sense stopMusic, ja s'ha parat en destructor de TITOL)
Audio::get()->playMusic("game.ogg");
} }
void EscenaJoc::actualitzar(float delta_time) { void EscenaJoc::actualitzar(float delta_time) {
@@ -150,6 +153,8 @@ void EscenaJoc::actualitzar(float delta_time) {
game_over_timer_ -= delta_time; game_over_timer_ -= delta_time;
if (game_over_timer_ <= 0.0f) { if (game_over_timer_ <= 0.0f) {
// Aturar música de joc abans de tornar al títol
Audio::get()->stopMusic();
// Auto-transition to title screen // Auto-transition to title screen
GestorEscenes::actual = GestorEscenes::Escena::TITOL; GestorEscenes::actual = GestorEscenes::Escena::TITOL;
return; return;

View File

@@ -200,6 +200,10 @@ void EscenaLogo::canviar_estat(EstatAnimacio nou_estat) {
std::mt19937 g(rd()); std::mt19937 g(rd());
std::shuffle(ordre_explosio_.begin(), ordre_explosio_.end(), g); std::shuffle(ordre_explosio_.begin(), ordre_explosio_.end(), g);
} }
else if (nou_estat == EstatAnimacio::POST_EXPLOSION)
{
Audio::get()->playMusic("title.ogg");
}
std::cout << "[EscenaLogo] Canvi a estat: " << static_cast<int>(nou_estat) std::cout << "[EscenaLogo] Canvi a estat: " << static_cast<int>(nou_estat)
<< "\n"; << "\n";
@@ -288,6 +292,7 @@ void EscenaLogo::actualitzar(float delta_time) {
case EstatAnimacio::POST_EXPLOSION: case EstatAnimacio::POST_EXPLOSION:
if (temps_estat_actual_ >= DURACIO_POST_EXPLOSION) { if (temps_estat_actual_ >= DURACIO_POST_EXPLOSION) {
// Iniciar música de títol abans de la transició
GestorEscenes::actual = GestorEscenes::Escena::TITOL; GestorEscenes::actual = GestorEscenes::Escena::TITOL;
} }
break; break;

View File

@@ -9,7 +9,7 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "../effects/debris_manager.hpp" #include "game/effects/debris_manager.hpp"
#include "core/defaults.hpp" #include "core/defaults.hpp"
#include "core/graphics/shape.hpp" #include "core/graphics/shape.hpp"
#include "core/rendering/sdl_manager.hpp" #include "core/rendering/sdl_manager.hpp"

View File

@@ -4,6 +4,7 @@
#include "escena_titol.hpp" #include "escena_titol.hpp"
#include <cfloat> #include <cfloat>
#include <cmath>
#include <iostream> #include <iostream>
#include <string> #include <string>
@@ -15,6 +16,11 @@
#include "core/system/global_events.hpp" #include "core/system/global_events.hpp"
#include "project.h" #include "project.h"
namespace {
// Brightness del starfield (1.0 = default, >1.0 més brillant, <1.0 menys brillant)
constexpr float BRIGHTNESS_STARFIELD = 1.2f;
} // namespace
EscenaTitol::EscenaTitol(SDLManager& sdl) EscenaTitol::EscenaTitol(SDLManager& sdl)
: sdl_(sdl), : sdl_(sdl),
text_(sdl.obte_renderer()), text_(sdl.obte_renderer()),
@@ -40,8 +46,21 @@ EscenaTitol::EscenaTitol(SDLManager& sdl)
150 // densitat: 150 estrelles (50 per capa) 150 // densitat: 150 estrelles (50 per capa)
); );
// Configurar brightness del starfield
starfield_->set_brightness(BRIGHTNESS_STARFIELD);
// Inicialitzar lletres del títol "ORNI ATTACK!" // Inicialitzar lletres del títol "ORNI ATTACK!"
inicialitzar_titol(); inicialitzar_titol();
// Iniciar música de títol si no està sonant
if (Audio::get()->getMusicState() != Audio::MusicState::PLAYING) {
Audio::get()->playMusic("title.ogg");
}
}
EscenaTitol::~EscenaTitol() {
// Aturar música de títol quan es destrueix l'escena
Audio::get()->stopMusic();
} }
void EscenaTitol::inicialitzar_titol() { void EscenaTitol::inicialitzar_titol() {
@@ -256,9 +275,18 @@ void EscenaTitol::actualitzar(float delta_time) {
estat_actual_ = EstatTitol::MAIN; estat_actual_ = EstatTitol::MAIN;
} }
break; break;
case EstatTitol::MAIN: case EstatTitol::MAIN:
// No hi ha lògica d'actualització en l'estat MAIN // No hi ha lògica d'actualització en l'estat MAIN
break; break;
case EstatTitol::TRANSITION:
temps_acumulat_ += delta_time;
if (temps_acumulat_ >= DURACIO_TRANSITION) {
// Transició a JOC (la música ja s'ha parat en el fade)
GestorEscenes::actual = GestorEscenes::Escena::JOC;
}
break;
} }
} }
@@ -273,8 +301,8 @@ void EscenaTitol::dibuixar() {
return; return;
} }
// Estat MAIN: Dibuixar títol i text (sobre el starfield) // Estat MAIN i TRANSITION: Dibuixar títol i text (sobre el starfield)
if (estat_actual_ == EstatTitol::MAIN) { if (estat_actual_ == EstatTitol::MAIN || estat_actual_ == EstatTitol::TRANSITION) {
// === Dibuixar lletres del títol "ORNI ATTACK!" === // === Dibuixar lletres del títol "ORNI ATTACK!" ===
// Dibuixar "ORNI" (línia 1) // Dibuixar "ORNI" (línia 1)
@@ -303,19 +331,31 @@ void EscenaTitol::dibuixar() {
); );
} }
// === Text "PRESS BUTTON TO PLAY" (a sota del títol) === // === Text "PRESS BUTTON TO PLAY" ===
const std::string main_text = "PRESS BUTTON TO PLAY"; // En estat MAIN: sempre visible
const float escala_main = 1.0f; // En estat TRANSITION: parpellejant (blink amb sinusoide)
const float spacing = 2.0f;
float text_width = text_.get_text_width(main_text, escala_main, spacing); const float spacing = 2.0f; // Espai entre caràcters (usat també per copyright)
float x_center = (Defaults::Game::WIDTH - text_width) / 2.0f; bool mostrar_text = true;
// Usar posició dinàmica: ATTACK + altura lletres + separació if (estat_actual_ == EstatTitol::TRANSITION) {
float altura_attack = lletres_attack_.empty() ? 50.0f : lletres_attack_[0].altura; // Parpelleig: sin oscil·la entre -1 i 1, volem ON quan > 0
float y_center = y_attack_dinamica_ + altura_attack + 70.0f; // 70px sota "ATTACK!" float fase = temps_acumulat_ * BLINK_FREQUENCY * 2.0f * 3.14159f; // 2π × freq × temps
mostrar_text = (std::sin(fase) > 0.0f);
}
text_.render(main_text, Punt{x_center, y_center}, escala_main, spacing); if (mostrar_text) {
const std::string main_text = "PRESS BUTTON TO PLAY";
const float escala_main = 1.0f;
float text_width = text_.get_text_width(main_text, escala_main, spacing);
float x_center = (Defaults::Game::WIDTH - text_width) / 2.0f;
float altura_attack = lletres_attack_.empty() ? 50.0f : lletres_attack_[0].altura;
float y_center = y_attack_dinamica_ + altura_attack + 70.0f;
text_.render(main_text, Punt{x_center, y_center}, escala_main, spacing);
}
// === Copyright a la part inferior (centrat horitzontalment) === // === Copyright a la part inferior (centrat horitzontalment) ===
// Convert to uppercase since VectorText only supports A-Z // Convert to uppercase since VectorText only supports A-Z
@@ -346,9 +386,16 @@ void EscenaTitol::processar_events(const SDL_Event& event) {
// Saltar a MAIN // Saltar a MAIN
estat_actual_ = EstatTitol::MAIN; estat_actual_ = EstatTitol::MAIN;
break; break;
case EstatTitol::MAIN: case EstatTitol::MAIN:
// Anar al joc // Iniciar transició amb fade-out de música
GestorEscenes::actual = GestorEscenes::Escena::JOC; estat_actual_ = EstatTitol::TRANSITION;
temps_acumulat_ = 0.0f; // Reset del comptador
Audio::get()->fadeOutMusic(MUSIC_FADE); // Fade de 300ms
break;
case EstatTitol::TRANSITION:
// Ignorar inputs durant la transició
break; break;
} }
} }

View File

@@ -19,22 +19,24 @@
class EscenaTitol { class EscenaTitol {
public: public:
explicit EscenaTitol(SDLManager& sdl); explicit EscenaTitol(SDLManager& sdl);
~EscenaTitol(); // Destructor per aturar música
void executar(); // Bucle principal de l'escena void executar(); // Bucle principal de l'escena
private: private:
// Màquina d'estats per la pantalla de títol // Màquina d'estats per la pantalla de títol
enum class EstatTitol { enum class EstatTitol {
INIT, // Pantalla negra inicial (2 segons) INIT, // Pantalla negra inicial (2 segons)
MAIN // Pantalla de títol amb text MAIN, // Pantalla de títol amb text
TRANSITION // Transició amb fade-out de música i text parpellejant
}; };
// Estructura per emmagatzemar informació de cada lletra del títol // Estructura per emmagatzemar informació de cada lletra del títol
struct LetraLogo { struct LetraLogo {
std::shared_ptr<Graphics::Shape> forma; // Forma vectorial de la lletra std::shared_ptr<Graphics::Shape> forma; // Forma vectorial de la lletra
Punt posicio; // Posició en pantalla Punt posicio; // Posició en pantalla
float ancho; // Amplada escalada float ancho; // Amplada escalada
float altura; // Altura escalada float altura; // Altura escalada
float offset_centre; // Offset del centre per posicionament float offset_centre; // Offset del centre per posicionament
}; };
SDLManager& sdl_; SDLManager& sdl_;
@@ -49,11 +51,14 @@ class EscenaTitol {
float y_attack_dinamica_; // Posició Y calculada dinàmicament per "ATTACK!" float y_attack_dinamica_; // Posició Y calculada dinàmicament per "ATTACK!"
// Constants // Constants
static constexpr float DURACIO_INIT = 2.0f; // Duració de l'estat INIT (2 segons) static constexpr float DURACIO_INIT = 4.0f; // Duració de l'estat INIT (2 segons)
static constexpr float ESCALA_TITULO = 0.6f; // Escala per les lletres del títol (50%) static constexpr float DURACIO_TRANSITION = 1.5f; // Duració de la transició (1.5 segons)
static constexpr float ESCALA_TITULO = 0.6f; // Escala per les lletres del títol (50%)
static constexpr float ESPAI_ENTRE_LLETRES = 10.0f; // Espai entre lletres static constexpr float ESPAI_ENTRE_LLETRES = 10.0f; // Espai entre lletres
static constexpr float Y_ORNI = 150.0f; // Posició Y de "ORNI" static constexpr float Y_ORNI = 150.0f; // Posició Y de "ORNI"
static constexpr float SEPARACION_LINEAS = 10.0f; // Separació entre "ORNI" i "ATTACK!" (0.0f = pegades) static constexpr float SEPARACION_LINEAS = 10.0f; // Separació entre "ORNI" i "ATTACK!" (0.0f = pegades)
static constexpr float BLINK_FREQUENCY = 3.0f; // Freqüència de parpelleig (3 Hz)
static constexpr int MUSIC_FADE = 1000; // Duracio del fade de la musica del titol al començar a jugar
// Mètodes privats // Mètodes privats
void actualitzar(float delta_time); void actualitzar(float delta_time);