tots els singletons tornats a fer a la vieja y gorda usanza

This commit is contained in:
2025-05-30 10:17:41 +02:00
parent 64b6f66044
commit f661da5215
29 changed files with 322 additions and 379 deletions

View File

@@ -5,27 +5,17 @@
#include <string> // Para allocator, string, char_traits, operator+
#include "utils.h" // Para getFileName
// Instancia estática del singleton
std::unique_ptr<Asset> Asset::instance_ = nullptr;
// Singleton
Asset *Asset::instance_ = nullptr;
// Inicializa la instancia única del singleton
void Asset::init(const std::string &executable_path)
{
if (!instance_)
instance_ = std::unique_ptr<Asset>(new Asset(executable_path));
}
void Asset::init(const std::string &executable_path) { Asset::instance_ = new Asset(executable_path); }
// Libera la instancia única
void Asset::destroy()
{
instance_.reset();
}
// Libera la instancia
void Asset::destroy() { delete Asset::instance_; }
// Obtiene la instancia única
Asset *Asset::get()
{
return instance_.get();
}
// Obtiene la instancia
Asset *Asset::get() { return Asset::instance_; }
// Añade un elemento a la lista
void Asset::add(const std::string &file, AssetType type, bool required, bool absolute)

View File

@@ -3,6 +3,7 @@
#include <string>
#include <vector>
#include <memory>
#include <iostream>
#include "utils.h"
// Tipos de recursos gestionados por Asset
@@ -24,31 +25,19 @@ enum class AssetType : int
class Asset
{
public:
// Inicializa la instancia única del singleton
static void init(const std::string &executable_path);
// --- Métodos de singleton ---
static void init(const std::string &executable_path); // Inicializa el objeto Asset
static void destroy(); // Libera el objeto Asset
static Asset *get(); // Obtiene el puntero al objeto Asset
// Libera la instancia única
static void destroy();
// Obtiene la instancia única
static Asset *get();
// Añade un recurso a la lista
void add(const std::string &file, AssetType type, bool required = true, bool absolute = false);
// Obtiene la ruta completa de un recurso a partir de su nombre
std::string get(const std::string &text) const;
// Verifica la existencia de todos los recursos requeridos
bool check() const;
// Devuelve una lista de archivos de un tipo concreto
std::vector<std::string> getListByType(AssetType type) const;
// --- Métodos para la gestión de recursos ---
void add(const std::string &file, AssetType type, bool required = true, bool absolute = false); // Añade un recurso a la lista
std::string get(const std::string &text) const; // Obtiene la ruta completa de un recurso a partir de su nombre
bool check() const; // Verifica la existencia de todos los recursos requeridos
std::vector<std::string> getListByType(AssetType type) const; // Devuelve una lista de archivos de un tipo concreto
private:
friend std::unique_ptr<Asset>::deleter_type;
// Estructura interna para almacenar información de cada recurso
// --- Estructura interna para almacenar información de cada recurso ---
struct AssetItem
{
std::string file; // Ruta del fichero desde la raíz del directorio
@@ -59,21 +48,22 @@ private:
: file(filePath), type(assetType), required(isRequired) {}
};
// Variables internas
// --- Variables internas ---
int longest_name_ = 0; // Longitud del nombre más largo
std::vector<AssetItem> file_list_; // Lista con todas las rutas de recursos
std::string executable_path_; // Ruta del ejecutable
// Métodos internos
// --- Métodos internos ---
bool checkFile(const std::string &path) const; // Verifica si un archivo existe
std::string getTypeName(AssetType type) const; // Devuelve el nombre textual del tipo de recurso
// Patrón Singleton: constructor y destructor privados, sin copia ni asignación
Asset(const std::string &executable_path)
: executable_path_(executable_path) {};
// --- Patrón Singleton ---
explicit Asset(const std::string &executable_path)
: executable_path_(executable_path) {}
~Asset() = default;
Asset(const Asset &) = delete;
Asset &operator=(const Asset &) = delete;
static std::unique_ptr<Asset> instance_;
// --- Singleton ---
static Asset *instance_;
};

View File

@@ -4,6 +4,18 @@
#include "resource.h"
#include <SDL3/SDL.h>
// Singleton
Audio *Audio::instance_ = nullptr;
// Inicializa la instancia única del singleton
void Audio::init() { Audio::instance_ = new Audio(); }
// Libera la instancia
void Audio::destroy() { delete Audio::instance_; }
// Obtiene la instancia
Audio *Audio::get() { return Audio::instance_; }
// Constructor
Audio::Audio()
{
@@ -26,10 +38,7 @@ Audio::Audio()
}
// Destructor
Audio::~Audio()
{
JA_Quit();
}
Audio::~Audio() { JA_Quit(); }
// Reproduce la música
void Audio::playMusic(const std::string &name, const int loop)

View File

@@ -6,55 +6,55 @@
class Audio
{
public:
// === Singleton ===
// Obtención de la instancia única (Meyers Singleton)
static Audio &get()
{
static Audio instance;
return instance;
}
// --- Métodos de singleton ---
static void init(); // Inicializa el objeto Audio
static void destroy(); // Libera el objeto Audio
static Audio *get(); // Obtiene el puntero al objeto Audio
// === Control de Música ===
// --- Control de Música ---
void playMusic(const std::string &name, int loop = -1); // Reproducir música en bucle
void pauseMusic(); // Pausar reproducción de música
void stopMusic(); // Detener completamente la música
void fadeOutMusic(int milliseconds); // Fundido de salida de la música
// === Control de Sonidos ===
// --- Control de Sonidos ---
void playSound(const std::string &name); // Reproducir sonido puntual
void stopAllSounds(); // Detener todos los sonidos
// === Configuración General ===
// --- Configuración General ---
void enable() { enabled_ = true; } // Habilitar audio
void disable() { enabled_ = false; } // Deshabilitar audio
void enable(bool value) { enabled_ = value; } // Establecer estado general
void toggleEnabled() { enabled_ = !enabled_; } // Alternar estado general
// === Configuración de Sonidos ===
// --- Configuración de Sonidos ---
void enableSound() { sound_enabled_ = true; } // Habilitar sonidos
void disableSound() { sound_enabled_ = false; } // Deshabilitar sonidos
void enableSound(bool value) { sound_enabled_ = value; } // Establecer estado de sonidos
void toggleSound() { sound_enabled_ = !sound_enabled_; } // Alternar estado de sonidos
// === Configuración de Música ===
// --- Configuración de Música ---
void enableMusic() { music_enabled_ = true; } // Habilitar música
void disableMusic() { music_enabled_ = false; } // Deshabilitar música
void enableMusic(bool value) { music_enabled_ = value; } // Establecer estado de música
void toggleMusic() { music_enabled_ = !music_enabled_; } // Alternar estado de música
// === Control de Volumen ===
// --- Control de Volumen ---
void setSoundVolume(int volume); // Ajustar volumen de efectos
void setMusicVolume(int volume); // Ajustar volumen de música
private:
// === Variables de Estado ===
// --- Variables de Estado ---
bool enabled_ = true; // Estado general del audio
bool sound_enabled_ = true; // Estado de los efectos de sonido
bool music_enabled_ = true; // Estado de la música
// === Patrón Singleton ===
// --- Patrón Singleton ---
Audio(); // Constructor privado
~Audio(); // Destructor privado
Audio(const Audio &) = delete; // Evitar copia
Audio &operator=(const Audio &) = delete; // Evitar asignación
// --- Singleton ---
static Audio *instance_;
};

View File

@@ -414,6 +414,6 @@ void Balloon::playSound()
{
if (sound_enabled_)
{
Audio::get().playSound(sound_);
Audio::get()->playSound(sound_);
}
}

View File

@@ -320,7 +320,7 @@ int BalloonManager::destroyAllBalloons()
}
balloon_deploy_counter_ = 300;
Audio::get().playSound("power_ball_explosion.wav");
Audio::get()->playSound("power_ball_explosion.wav");
Screen::get()->flash(FLASH_COLOR, 3);
Screen::get()->shake();

View File

@@ -71,7 +71,7 @@ Credits::~Credits()
SDL_DestroyTexture(text_texture_);
SDL_DestroyTexture(canvas_);
resetVolume();
Audio::get().stopMusic();
Audio::get()->stopMusic();
}
// Bucle principal
@@ -437,7 +437,7 @@ void Credits::updateBlackRects()
{
// Si los rectangulos izquierdo y derecho han llegado al centro
setVolume(0);
Audio::get().stopMusic();
Audio::get()->stopMusic();
if (counter_pre_fade_ == 400)
{
fade_out_->activate();
@@ -471,7 +471,7 @@ void Credits::updateAllFades()
fade_in_->update();
if (fade_in_->hasEnded())
{
Audio::get().playMusic("credits.ogg");
Audio::get()->playMusic("credits.ogg");
}
fade_out_->update();
@@ -485,14 +485,14 @@ void Credits::updateAllFades()
void Credits::setVolume(int amount)
{
options.audio.music.volume = std::clamp(amount, 0, 100);
Audio::get().setMusicVolume(options.audio.music.volume);
Audio::get()->setMusicVolume(options.audio.music.volume);
}
// Reestablece el nivel de volumen
void Credits::resetVolume()
{
options.audio.music.volume = initial_volume_;
Audio::get().setMusicVolume(options.audio.music.volume);
Audio::get()->setMusicVolume(options.audio.music.volume);
}
// Cambia el color del fondo

View File

@@ -16,48 +16,51 @@ class Fade;
class Player;
class TiledBG;
constexpr int PLAY_AREA_HEIGHT = 200;
class Credits
{
public:
// --- Constructores y destructor ---
Credits();
~Credits();
void run(); // Bucle principal
// --- Bucle principal ---
void run();
private:
// === Objetos Principales ===
// --- Constantes de clase ---
static constexpr int PLAY_AREA_HEIGHT = 200;
// --- Objetos principales ---
std::unique_ptr<BalloonManager> balloon_manager_; // Gestión de globos
std::unique_ptr<TiledBG> tiled_bg_; // Mosaico animado de fondo
std::unique_ptr<Fade> fade_in_; // Fundido de entrada
std::unique_ptr<Fade> fade_out_; // Fundido de salida
std::vector<std::shared_ptr<Player>> players_; // Vector de jugadores
// === Gestión de Texturas ===
SDL_Texture *text_texture_; // Textura con el texto
SDL_Texture *canvas_; // Textura donde dibujarlo todo
// --- Gestión de texturas ---
SDL_Texture *text_texture_; // Textura con el texto de créditos
SDL_Texture *canvas_; // Textura donde se dibuja todo
// === Temporización y Contadores ===
// --- Temporización y contadores ---
Uint64 ticks_ = 0; // Control de velocidad del programa
Uint32 counter_ = 0; // Contador principal de lógica
Uint32 counter_pre_fade_ = 0; // Activación del fundido final
Uint32 counter_prevent_endless_ = 0; // Prevención de bucle infinito
// === Variables de Estado ===
// --- Variables de estado ---
bool fading_ = false; // Estado del fade final
bool want_to_pass_ = false; // Jugador quiere saltarse créditos
bool mini_logo_on_position_ = false; // Minilogo en posición final
// === Diseño y Posicionamiento ===
float black_bars_size_ = (param.game.game_area.rect.h - PLAY_AREA_HEIGHT) / 2;
// --- Diseño y posicionamiento ---
float black_bars_size_ = (param.game.game_area.rect.h - PLAY_AREA_HEIGHT) / 2; // Tamaño de las barras negras
int mini_logo_final_pos_ = 0; // Posición final del minilogo
// === Control de Audio ===
// --- Control de audio ---
int initial_volume_ = options.audio.music.volume; // Volumen inicial
int steps_ = 0; // Pasos para reducir audio
// === Rectángulos de Renderizado ===
// --- Rectángulos de renderizado ---
// Texto de créditos
SDL_FRect credits_rect_src_ = param.game.game_area.rect;
SDL_FRect credits_rect_dst_ = param.game.game_area.rect;
@@ -98,28 +101,28 @@ private:
// Borde para la ventana
SDL_FRect red_rect = play_area_; // Delimitador de ventana
// === Métodos del Bucle Principal ===
void update(); // Actualización principal
void render(); // Renderizado
// --- Métodos del bucle principal ---
void update(); // Actualización principal de la lógica
void render(); // Renderizado de la escena
void checkEvents(); // Manejo de eventos
void checkInput(); // Procesamiento de entrada
// === Métodos de Renderizado ===
void fillTextTexture(); // Crear textura de texto
void fillCanvas(); // Renderizar todos los sprites
// --- Métodos de renderizado ---
void fillTextTexture(); // Crear textura de texto de créditos
void fillCanvas(); // Renderizar todos los sprites y fondos
void updateTextureDstRects(); // Actualizar destinos de texturas
// === Métodos de Lógica del Juego ===
// --- Métodos de lógica del juego ---
void throwBalloons(); // Lanzar globos al escenario
void initPlayers(); // Inicializar jugadores
void updateAllFades(); // Actualizar estados de fade
void cycleColors(); // Cambiar colores de fondo
// === Métodos de Interfaz ===
void updateBlackRects(); // Actualizar rectángulos negros
void updateRedRect(); // Actualizar rectángulo rojo
// --- Métodos de interfaz ---
void updateBlackRects(); // Actualizar rectángulos negros (letterbox)
void updateRedRect(); // Actualizar rectángulo rojo (borde)
// === Métodos de Audio ===
// --- Métodos de audio ---
void setVolume(int amount); // Establecer volumen
void resetVolume(); // Restablecer volumen
};

View File

@@ -34,6 +34,7 @@
#include "resource.h" // Para Resource
#include "screen.h" // Para Screen
#include "section.h" // Para Name, Options, name, options
#include "service_menu.h" // Para ServiceMenu
#include "title.h" // Para Title
#include "utils.h" // Para Overrides, overrides
@@ -91,13 +92,14 @@ void Director::init()
loadParams(); // Carga los parámetros del programa
loadScoreFile(); // Carga el archivo de puntuaciones
// Inicialización de subsistemas
// Inicialización de subsistemas principales
lang::loadFromFile(getLangFile(static_cast<lang::Code>(options.game.language))); // Carga el archivo de idioma
Screen::init(); // Inicializa la pantalla y el sistema de renderizado
Audio::get(); // Activa el sistema de audio
Audio::init(); // Activa el sistema de audio
Resource::init(); // Inicializa el sistema de gestión de recursos
Input::init(Asset::get()->get("gamecontrollerdb.txt")); // Carga configuración de controles
bindInputs(); // Asigna los controles a la entrada del sistema
ServiceMenu::init(); // Inicializa el menú de servicio
// Inicialización del sistema de notificaciones
Notifier::init(std::string(), Resource::get()->getText("8bithud"));
@@ -109,20 +111,26 @@ void Director::init()
#endif
}
// Cierra todo
// Cierra todo y libera recursos del sistema y de los singletons
void Director::close()
{
// Guarda las opciones actuales en el archivo de configuración
saveOptionsFile(Asset::get()->get("config.txt"));
Notifier::destroy();
Input::destroy();
Resource::destroy();
Screen::destroy();
Asset::destroy();
// Libera los singletons y recursos en orden inverso al de inicialización
Notifier::destroy(); // Libera el sistema de notificaciones
ServiceMenu::destroy(); // Libera el sistema de menú de servicio
Input::destroy(); // Libera el sistema de entrada
Resource::destroy(); // Libera el sistema de recursos gráficos y de texto
Audio::destroy(); // Libera el sistema de audio
Screen::destroy(); // Libera el sistema de pantalla y renderizado
Asset::destroy(); // Libera el gestor de archivos
// Libera todos los recursos de SDL
SDL_Quit();
#ifdef ARCADE
// Si está en modo arcade, apaga el sistema si corresponde
shutdownSystem(section::options == section::Options::QUIT_WITH_CONTROLLER);
#endif
}
@@ -460,7 +468,7 @@ void Director::setFileList()
void Director::checkProgramArguments(int argc, const char *argv[])
{
// Establece la ruta del programa
executable_path_ = argv[0];
executable_path_ = getPath(argv[0]);
// Comprueba el resto de parámetros
for (int i = 1; i < argc; ++i)
@@ -605,8 +613,8 @@ void Director::runDemoGame()
// Ejecuta la sección init
void Director::runInit()
{
Audio::get().stopMusic();
Audio::get().stopAllSounds();
Audio::get()->stopMusic();
Audio::get()->stopAllSounds();
if (section::options == section::Options::RELOAD || true)
{
Resource::get()->reload();

View File

@@ -101,7 +101,7 @@ Game::~Game()
// [Modo DEMO] Vuelve a activar los sonidos
if (demo_.enabled)
{
Audio::get().enableSound();
Audio::get()->enableSound();
}
else
{
@@ -109,7 +109,7 @@ Game::~Game()
auto manager = std::make_unique<ManageHiScoreTable>(options.game.hi_score_table);
manager->saveToFile(Asset::get()->get("score.bin"));
section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
Audio::get().stopMusic();
Audio::get()->stopMusic();
}
#ifdef RECORDING
@@ -201,7 +201,7 @@ void Game::updateHiScore()
if (hi_score_achieved_ == false)
{
hi_score_achieved_ = true;
Audio::get().playSound("hi_score_achieved.wav");
Audio::get()->playSound("hi_score_achieved.wav");
}
}
}
@@ -259,7 +259,7 @@ void Game::updateStage()
// Cambio de fase
Stage::power = Stage::get(Stage::number).power_to_complete - Stage::power;
++Stage::number;
Audio::get().playSound("stage_change.wav");
Audio::get()->playSound("stage_change.wav");
balloon_manager_->resetBalloonSpeed();
screen_->flash(FLASH_COLOR, 3);
screen_->shake();
@@ -311,7 +311,7 @@ void Game::updateGameStateGameOver()
if (game_over_counter_ == GAME_OVER_COUNTER_)
{
createMessage({paths_.at(2), paths_.at(3)}, Resource::get()->getTexture("game_text_game_over"));
Audio::get().fadeOutMusic(1000);
Audio::get()->fadeOutMusic(1000);
balloon_manager_->setSounds(true);
}
@@ -328,7 +328,7 @@ void Game::updateGameStateGameOver()
if (options.audio.enabled)
{
const float VOL = static_cast<float>(64 * (100 - fade_out_->getValue())) / 100.0f;
Audio::get().setSoundVolume(static_cast<int>(VOL));
Audio::get()->setSoundVolume(static_cast<int>(VOL));
}
}
@@ -347,8 +347,8 @@ void Game::updateGameStateGameOver()
section::options = section::Options::HI_SCORE_AFTER_PLAYING;
if (options.audio.enabled)
{
Audio::get().stopAllSounds();
Audio::get().setSoundVolume(options.audio.sound.volume);
Audio::get()->stopAllSounds();
Audio::get()->setSoundVolume(options.audio.sound.volume);
}
}
}
@@ -481,7 +481,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
player->addScore(1000);
const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(0)->getWidth()) / 2;
createItemText(x, game_text_textures_.at(0));
Audio::get().playSound("item_pickup.wav");
Audio::get()->playSound("item_pickup.wav");
break;
}
case ItemType::GAVINA:
@@ -489,7 +489,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
player->addScore(2500);
const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(1)->getWidth()) / 2;
createItemText(x, game_text_textures_.at(1));
Audio::get().playSound("item_pickup.wav");
Audio::get()->playSound("item_pickup.wav");
break;
}
case ItemType::PACMAR:
@@ -497,7 +497,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
player->addScore(5000);
const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(2)->getWidth()) / 2;
createItemText(x, game_text_textures_.at(2));
Audio::get().playSound("item_pickup.wav");
Audio::get()->playSound("item_pickup.wav");
break;
}
case ItemType::DEBIAN:
@@ -505,7 +505,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
player->addScore(100000);
const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(6)->getWidth()) / 2;
createItemText(x, game_text_textures_.at(6));
Audio::get().playSound("debian_pickup.wav");
Audio::get()->playSound("debian_pickup.wav");
break;
}
case ItemType::CLOCK:
@@ -513,7 +513,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
enableTimeStopItem();
const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(5)->getWidth()) / 2;
createItemText(x, game_text_textures_.at(5));
Audio::get().playSound("item_pickup.wav");
Audio::get()->playSound("item_pickup.wav");
break;
}
case ItemType::COFFEE:
@@ -530,7 +530,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(4)->getWidth()) / 2;
createItemText(x, game_text_textures_.at(4));
}
Audio::get().playSound("voice_coffee.wav");
Audio::get()->playSound("voice_coffee.wav");
break;
}
case ItemType::COFFEE_MACHINE:
@@ -539,7 +539,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
coffee_machine_enabled_ = false;
const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(3)->getWidth()) / 2;
createItemText(x, game_text_textures_.at(3));
Audio::get().playSound("voice_power_up.wav");
Audio::get()->playSound("voice_power_up.wav");
break;
}
default:
@@ -568,7 +568,7 @@ void Game::checkBulletCollision()
if (tabe_->tryToGetBonus())
{
createItem(ItemType::DEBIAN, pos.x, pos.y);
Audio::get().playSound("debian_drop.wav");
Audio::get()->playSound("debian_drop.wav");
}
else
{
@@ -576,7 +576,7 @@ void Game::checkBulletCollision()
{
createItem(ItemType::COFFEE, pos.x, pos.y);
}
Audio::get().playSound("tabe_hit.wav");
Audio::get()->playSound("tabe_hit.wav");
}
break;
}
@@ -598,7 +598,7 @@ void Game::checkBulletCollision()
if (dropped_item != ItemType::COFFEE_MACHINE)
{
createItem(dropped_item, balloon->getPosX(), balloon->getPosY());
Audio::get().playSound("item_drop.wav");
Audio::get()->playSound("item_drop.wav");
}
else
{
@@ -620,7 +620,7 @@ void Game::checkBulletCollision()
updateHiScore();
// Sonido de explosión
Audio::get().playSound("balloon.wav");
Audio::get()->playSound("balloon.wav");
// Deshabilita la bala
bullet->disable();
@@ -676,7 +676,7 @@ void Game::updateItems()
item->update();
if (item->isOnFloor())
{
Audio::get().playSound("title.wav");
Audio::get()->playSound("title.wav");
screen_->shake();
}
}
@@ -903,16 +903,16 @@ void Game::killPlayer(std::shared_ptr<Player> &player)
// Lo pierde
player->removeExtraHit();
throwCoffee(player->getPosX() + (player->getWidth() / 2), player->getPosY() + (player->getHeight() / 2));
Audio::get().playSound("coffee_out.wav");
Audio::get()->playSound("coffee_out.wav");
screen_->shake();
}
else
{
// Si no tiene cafes, muere
balloon_manager_->stopAllBalloons();
Audio::get().playSound("player_collision.wav");
Audio::get()->playSound("player_collision.wav");
screen_->shake();
Audio::get().playSound("voice_no.wav");
Audio::get()->playSound("voice_no.wav");
player->setPlayingState(PlayerState::DYING);
if (allPlayersAreNotPlaying())
{
@@ -932,7 +932,7 @@ void Game::updateTimeStopped()
{
if (time_stopped_counter_ % 30 == 0)
{
Audio::get().playSound("clock.wav");
Audio::get()->playSound("clock.wav");
}
}
else
@@ -940,12 +940,12 @@ void Game::updateTimeStopped()
if (time_stopped_counter_ % 30 == 0)
{
balloon_manager_->normalColorsToAllBalloons();
Audio::get().playSound("clock.wav");
Audio::get()->playSound("clock.wav");
}
else if (time_stopped_counter_ % 30 == 15)
{
balloon_manager_->reverseColorsToAllBalloons();
Audio::get().playSound("clock.wav");
Audio::get()->playSound("clock.wav");
}
}
}
@@ -1427,7 +1427,7 @@ void Game::handleFireInput(const std::shared_ptr<Player> &player, BulletType bul
player->setInput(bulletType == BulletType::UP ? InputAction::FIRE_CENTER : bulletType == BulletType::LEFT ? InputAction::FIRE_LEFT
: InputAction::FIRE_RIGHT);
createBullet(player->getPosX() + (player->getWidth() / 2) - 6, player->getPosY() + (player->getHeight() / 2), bulletType, player->isPowerUp(), player->getId());
Audio::get().playSound("bullet.wav");
Audio::get()->playSound("bullet.wav");
// Establece un tiempo de espera para el próximo disparo.
const int cooldown = player->isPowerUp() ? 5 : options.game.autofire ? 10
@@ -1629,7 +1629,7 @@ void Game::initDemo(int player_id)
}
// Deshabilita los sonidos
Audio::get().disableSound();
Audio::get()->disableSound();
// Configura los marcadores
scoreboard_->setMode(SCOREBOARD_LEFT_PANEL, ScoreboardMode::DEMO);
@@ -1731,7 +1731,7 @@ void Game::initPlayers(int player_id)
// Hace sonar la música
void Game::playMusic()
{
Audio::get().playMusic("playing.ogg");
Audio::get()->playMusic("playing.ogg");
}
// Detiene la música
@@ -1739,7 +1739,7 @@ void Game::stopMusic()
{
if (!demo_.enabled)
{
Audio::get().stopMusic();
Audio::get()->stopMusic();
}
}
@@ -1823,7 +1823,7 @@ void Game::updateGameStateEnteringPlayer()
{
setState(GameState::SHOWING_GET_READY_MESSAGE);
createMessage({paths_.at(0), paths_.at(1)}, Resource::get()->getTexture("game_text_get_ready"));
Audio::get().playSound("voice_get_ready.wav");
Audio::get()->playSound("voice_get_ready.wav");
}
}
}

View File

@@ -123,7 +123,7 @@ void GameLogo::update()
coffee_crisis_status_ = Status::SHAKING;
// Reproduce el efecto sonoro
Audio::get().playSound("title.wav");
Audio::get()->playSound("title.wav");
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGHT, FLASH_DELAY);
Screen::get()->shake();
}
@@ -187,7 +187,7 @@ void GameLogo::update()
zoom_ = 1.0f;
arcade_edition_sprite_->setZoom(zoom_);
shake_.init(1, 2, 8, arcade_edition_sprite_->getX());
Audio::get().playSound("title.wav");
Audio::get()->playSound("title.wav");
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGHT, FLASH_DELAY);
Screen::get()->shake();
}

View File

@@ -60,7 +60,7 @@ namespace globalInputs
void toggleAudio()
{
options.audio.enabled = !options.audio.enabled;
Audio::get().enable(options.audio.enabled);
Audio::get()->enable(options.audio.enabled);
Notifier::get()->show({"Audio " + boolToOnOff(options.audio.enabled)});
}
@@ -151,7 +151,7 @@ namespace globalInputs
switch (section::name)
{
case section::Name::INTRO:
Audio::get().stopMusic();
Audio::get()->stopMusic();
/* Continua en el case de abajo */
case section::Name::LOGO:
case section::Name::HI_SCORE_TABLE:

View File

@@ -150,7 +150,7 @@ void HiScoreTable::checkInput()
// Bucle para la pantalla de instrucciones
void HiScoreTable::run()
{
Audio::get().playMusic("title.ogg");
Audio::get()->playMusic("title.ogg");
while (section::name == section::Name::HI_SCORE_TABLE)
{
checkInput();

View File

@@ -8,26 +8,17 @@
#include <unordered_map> // Para unordered_map, operator==, _Node_cons...
#include <utility> // Para pair
// [SINGLETON]
Input *Input::input_ = nullptr;
// Singleton
Input *Input::instance_ = nullptr;
// [SINGLETON] Crearemos el objeto con esta función estática
void Input::init(const std::string &game_controller_db_path)
{
Input::input_ = new Input(game_controller_db_path);
}
// Inicializa la instancia única del singleton
void Input::init(const std::string &game_controller_db_path) { Input::instance_ = new Input(game_controller_db_path); }
// [SINGLETON] Destruiremos el objeto con esta función estática
void Input::destroy()
{
delete Input::input_;
}
// Libera la instancia
void Input::destroy() { delete Input::instance_; }
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
Input *Input::get()
{
return Input::input_;
}
// Obtiene la instancia
Input *Input::get() { return Input::instance_; }
// Constructor
Input::Input(const std::string &game_controller_db_path)

View File

@@ -69,66 +69,40 @@ enum class InputDeviceToUse : int
class Input
{
public:
// [SINGLETON] Crearemos el objeto con esta función estática
static void init(const std::string &game_controller_db_path);
// --- Métodos de singleton ---
static void init(const std::string &game_controller_db_path); // Inicializa el singleton
static void destroy(); // Libera el singleton
static Input *get(); // Obtiene la instancia
// [SINGLETON] Destruiremos el objeto con esta función estática
static void destroy();
// --- Métodos de configuración de controles ---
void bindKey(InputAction input, SDL_Scancode code); // Asigna inputs a teclas
void bindGameControllerButton(int controller_index, InputAction input, SDL_GamepadButton button); // Asigna inputs a botones del mando
void bindGameControllerButton(int controller_index, InputAction inputTarget, InputAction inputSource); // Asigna inputs a otros inputs del mando
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
static Input *get();
// --- Métodos de consulta de entrada ---
bool checkInput(InputAction input, bool repeat = true, InputDeviceToUse device = InputDeviceToUse::ANY, int controller_index = 0); // Comprueba si un input está activo
bool checkAnyInput(InputDeviceToUse device = InputDeviceToUse::ANY, int controller_index = 0); // Comprueba si hay al menos un input activo
int checkAnyButtonPressed(bool repeat = INPUT_DO_NOT_ALLOW_REPEAT); // Comprueba si hay algún botón pulsado
// Asigna inputs a teclas
void bindKey(InputAction input, SDL_Scancode code);
// --- Métodos de gestión de mandos ---
bool discoverGameControllers(); // Busca si hay mandos conectados
bool gameControllerFound(); // Comprueba si hay algún mando conectado
int getNumControllers() const; // Obtiene el número de mandos conectados
std::string getControllerName(int controller_index) const; // Obtiene el nombre de un mando de juego
int getJoyIndex(SDL_JoystickID id) const; // Obtiene el índice del controlador a partir de un event.id
// Asigna inputs a botones del mando
void bindGameControllerButton(int controller_index, InputAction input, SDL_GamepadButton button);
void bindGameControllerButton(int controller_index, InputAction inputTarget, InputAction inputSource);
// Comprueba si un input está activo
bool checkInput(InputAction input, bool repeat = true, InputDeviceToUse device = InputDeviceToUse::ANY, int controller_index = 0);
// Comprueba si hay al menos un input activo
bool checkAnyInput(InputDeviceToUse device = InputDeviceToUse::ANY, int controller_index = 0);
// Comprueba si hay algún botón pulsado
int checkAnyButtonPressed(bool repeat = INPUT_DO_NOT_ALLOW_REPEAT);
// Busca si hay mandos conectados
bool discoverGameControllers();
// Comprueba si hay algún mando conectado
bool gameControllerFound();
// Obtiene el número de mandos conectados
int getNumControllers() const;
// Obtiene el nombre de un mando de juego
std::string getControllerName(int controller_index) const;
// Obtiene el índice del controlador a partir de un event.id
int getJoyIndex(SDL_JoystickID id) const;
// Muestra por consola los controles asignados
void printBindings(InputDeviceToUse device = InputDeviceToUse::KEYBOARD, int controller_index = 0) const;
// Obtiene el SDL_GamepadButton asignado a un input
SDL_GamepadButton getControllerBinding(int controller_index, InputAction input) const;
// Convierte un InputAction a std::string
std::string to_string(InputAction input) const;
// Convierte un std::string a InputAction
InputAction to_inputs_e(const std::string &name) const;
// Obtiene el índice a partir del nombre del mando
int getIndexByName(const std::string &name) const;
// --- Métodos de consulta y utilidades ---
void printBindings(InputDeviceToUse device = InputDeviceToUse::KEYBOARD, int controller_index = 0) const; // Muestra por consola los controles asignados
SDL_GamepadButton getControllerBinding(int controller_index, InputAction input) const; // Obtiene el SDL_GamepadButton asignado a un input
std::string to_string(InputAction input) const; // Convierte un InputAction a std::string
InputAction to_inputs_e(const std::string &name) const; // Convierte un std::string a InputAction
int getIndexByName(const std::string &name) const; // Obtiene el índice a partir del nombre del mando
private:
// [SINGLETON] Objeto privado
static Input *input_;
// --- Singleton ---
static Input *instance_;
// Estructura para asociar teclas a acciones
// --- Estructuras internas ---
struct KeyBindings
{
Uint8 scancode; // Scancode asociado
@@ -138,7 +112,6 @@ private:
: scancode(sc), active(act) {}
};
// Estructura para asociar botones de mando a acciones
struct ControllerBindings
{
SDL_GamepadButton button; // GameControllerButton asociado
@@ -149,7 +122,7 @@ private:
: button(btn), active(act), axis_active(axis_act) {}
};
// Variables internas
// --- Variables internas ---
std::vector<SDL_Gamepad *> connected_controllers_; // Vector con todos los mandos conectados
std::vector<SDL_Joystick *> joysticks_; // Vector con todos los joysticks conectados
std::vector<KeyBindings> key_bindings_; // Vector con las teclas asociadas a los inputs predefinidos
@@ -160,14 +133,11 @@ private:
int num_gamepads_ = 0; // Número de mandos conectados
std::string game_controller_db_path_; // Ruta al archivo gamecontrollerdb.txt
// --- Métodos internos ---
void initSDL(); // Inicializa SDL para la gestión de mandos
bool checkAxisInput(InputAction input, int controller_index, bool repeat); // Comprueba el eje del mando
// Comprueba el eje del mando
bool checkAxisInput(InputAction input, int controller_index, bool repeat);
// Constructor privado
explicit Input(const std::string &game_controller_db_path);
// Destructor
~Input() = default;
// --- Constructor y destructor ---
explicit Input(const std::string &game_controller_db_path); // Constructor privado
~Input() = default; // Destructor privado
};

View File

@@ -272,7 +272,7 @@ void Instructions::checkInput()
// Bucle para la pantalla de instrucciones
void Instructions::run()
{
Audio::get().playMusic("title.ogg");
Audio::get()->playMusic("title.ogg");
while (section::name == section::Name::INSTRUCTIONS)
{
checkInput();

View File

@@ -281,7 +281,7 @@ void Intro::render()
// Bucle principal
void Intro::run()
{
Audio::get().playMusic("intro.ogg", 0);
Audio::get()->playMusic("intro.ogg", 0);
while (section::name == section::Name::INTRO)
{
checkInput();
@@ -513,7 +513,7 @@ void Intro::updatePostState()
// Finaliza la intro después de 1 segundo
if (ELAPSED_TIME >= 1000)
{
Audio::get().stopMusic();
Audio::get()->stopMusic();
section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1;
}

View File

@@ -60,7 +60,7 @@ Logo::~Logo()
{
jail_texture_->setColor(255, 255, 255);
since_texture_->setColor(255, 255, 255);
Audio::get().stopAllSounds();
Audio::get()->stopAllSounds();
}
// Comprueba el manejador de eventos
@@ -84,7 +84,7 @@ void Logo::updateJAILGAMES()
{
if (counter_ == 30)
{
Audio::get().playSound("logo.wav");
Audio::get()->playSound("logo.wav");
}
if (counter_ > 30)
@@ -181,7 +181,7 @@ void Logo::render()
// Bucle para el logo del juego
void Logo::run()
{
Audio::get().fadeOutMusic(300);
Audio::get()->fadeOutMusic(300);
while (section::name == section::Name::LOGO)
{
checkInput();

View File

@@ -12,26 +12,17 @@
#include "texture.h" // Para Texture
#include "resource.h"
// [SINGLETON]
Notifier *Notifier::notifier_ = nullptr;
// Singleton
Notifier *Notifier::instance_ = nullptr;
// [SINGLETON] Crearemos el objeto con esta función estática
void Notifier::init(const std::string &icon_file, std::shared_ptr<Text> text)
{
Notifier::notifier_ = new Notifier(icon_file, text);
}
// Inicializa la instancia única del singleton
void Notifier::init(const std::string &icon_file, std::shared_ptr<Text> text) { Notifier::instance_ = new Notifier(icon_file, text); }
// [SINGLETON] Destruiremos el objeto con esta función estática
void Notifier::destroy()
{
delete Notifier::notifier_;
}
// Libera la instancia
void Notifier::destroy() { delete Notifier::instance_; }
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
Notifier *Notifier::get()
{
return Notifier::notifier_;
}
// Obtiene la instancia
Notifier *Notifier::get() { return Notifier::instance_; }
// Constructor
Notifier::Notifier(std::string icon_file, std::shared_ptr<Text> text)
@@ -76,7 +67,7 @@ void Notifier::update()
if (notifications_[i].state == NotificationStatus::RISING)
{
// Reproduce el sonido de la notificación
Audio::get().playSound("notify.wav");
Audio::get()->playSound("notify.wav");
}
}
}

View File

@@ -15,36 +15,24 @@ class Texture;
class Notifier
{
public:
// [SINGLETON] Crearemos el objeto con esta función estática
static void init(const std::string &icon_file, std::shared_ptr<Text> text);
// --- Métodos de singleton ---
static void init(const std::string &icon_file, std::shared_ptr<Text> text); // Inicializa el singleton
static void destroy(); // Libera el singleton
static Notifier *get(); // Obtiene la instancia
// [SINGLETON] Destruiremos el objeto con esta función estática
static void destroy();
// --- Métodos principales ---
void render(); // Dibuja las notificaciones por pantalla
void update(); // Actualiza el estado de las notificaciones
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
static Notifier *get();
// Dibuja las notificaciones por pantalla
void render();
// Actualiza el estado de las notificaciones
void update();
// Muestra una notificación de texto por pantalla
void show(std::vector<std::string> texts, int icon = -1, const std::string &code = std::string());
// Indica si hay notificaciones activas
bool isActive() const { return !notifications_.empty(); }
// Obtiene los códigos de las notificaciones activas
std::vector<std::string> getCodes();
// Comprueba si hay alguna notificación con un código concreto
bool checkCode(const std::string &code) { return stringInVector(getCodes(), code); }
// --- Gestión de notificaciones ---
void show(std::vector<std::string> texts, int icon = -1, const std::string &code = std::string()); // Muestra una notificación de texto por pantalla
bool isActive() const { return !notifications_.empty(); } // Indica si hay notificaciones activas
std::vector<std::string> getCodes(); // Obtiene los códigos de las notificaciones activas
bool checkCode(const std::string &code) { return stringInVector(getCodes(), code); } // Comprueba si hay alguna notificación con un código concreto
private:
// [SINGLETON] Objeto notifier
static Notifier *notifier_;
// --- Singleton ---
static Notifier *instance_;
// --- Tipos internos ---
enum class NotificationStatus
@@ -97,7 +85,7 @@ private:
void clearFinishedNotifications(); // Elimina las notificaciones finalizadas
void clearAllNotifications(); // Finaliza y elimina todas las notificaciones activas
// [SINGLETON] Constructor y destructor privados
Notifier(std::string icon_file, std::shared_ptr<Text> text);
~Notifier() = default;
// --- Constructor y destructor ---
Notifier(std::string icon_file, std::shared_ptr<Text> text); // Constructor privado
~Notifier() = default; // Destructor privado
};

View File

@@ -221,7 +221,7 @@ void Player::move()
++step_counter_;
if (step_counter_ % 10 == 0)
{
Audio::get().playSound("walk.wav");
Audio::get()->playSound("walk.wav");
}
switch (id_)
@@ -252,7 +252,7 @@ void Player::move()
++step_counter_;
if (step_counter_ % 10 == 0)
{
Audio::get().playSound("walk.wav");
Audio::get()->playSound("walk.wav");
}
switch (id_)
@@ -752,7 +752,7 @@ void Player::decContinueCounter()
}
else
{
Audio::get().playSound("continue_clock.wav");
Audio::get()->playSound("continue_clock.wav");
}
}
@@ -798,5 +798,5 @@ void Player::shiftSprite()
void Player::playRandomBubbleSound()
{
const std::vector<std::string> sounds = {"bubble1.wav", "bubble2.wav", "bubble3.wav", "bubble4.wav"};
Audio::get().playSound(sounds.at(rand() % sounds.size()));
Audio::get()->playSound(sounds.at(rand() % sounds.size()));
}

View File

@@ -10,32 +10,20 @@
struct JA_Music_t; // lines 11-11
struct JA_Sound_t; // lines 12-12
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
Resource *Resource::resource_ = nullptr;
// Singleton
Resource *Resource::instance_ = nullptr;
// [SINGLETON] Crearemos el objeto screen con esta función estática
void Resource::init()
{
Resource::resource_ = new Resource();
}
// Inicializa la instancia única del singleton
void Resource::init() { Resource::instance_ = new Resource(); }
// [SINGLETON] Destruiremos el objeto screen con esta función estática
void Resource::destroy()
{
delete Resource::resource_;
}
// Libera la instancia
void Resource::destroy() { delete Resource::instance_; }
// [SINGLETON] Con este método obtenemos el objeto screen y podemos trabajar con él
Resource *Resource::get()
{
return Resource::resource_;
}
// Obtiene la instancia
Resource *Resource::get() { return Resource::instance_; }
// Constructor
Resource::Resource()
{
load();
}
Resource::Resource() { load(); }
// Vacia todos los vectores de recursos
void Resource::clear()

View File

@@ -97,7 +97,7 @@ public:
private:
// --- Singleton ---
static Resource *resource_;
static Resource *instance_;
// --- Vectores de recursos ---
std::vector<ResourceSound> sounds_; // Vector con los sonidos

View File

@@ -20,17 +20,17 @@
#include "resource.h" // Para Resource
#include "text.h" // Para Text
// [SINGLETON]
Screen *Screen::screen_ = nullptr;
// Singleton
Screen *Screen::instance_ = nullptr;
// [SINGLETON] Crearemos el objeto con esta función estática
void Screen::init() { Screen::screen_ = new Screen(); }
// Inicializa la instancia única del singleton
void Screen::init() { Screen::instance_ = new Screen(); }
// [SINGLETON] Destruiremos el objeto con esta función estática
void Screen::destroy() { delete Screen::screen_; }
// Libera la instancia
void Screen::destroy() { delete Screen::instance_; }
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
Screen *Screen::get() { return Screen::screen_; }
// Obtiene la instancia
Screen *Screen::get() { return Screen::instance_; }
// Constructor
Screen::Screen()

View File

@@ -178,7 +178,7 @@ private:
#endif
// --- Singleton ---
static Screen *screen_;
static Screen *instance_;
// --- Objetos y punteros ---
SDL_Window *window_; // Ventana de la aplicación

View File

@@ -1,6 +1,19 @@
#include "service_menu.h"
#include <iostream>
// Singleton
ServiceMenu *ServiceMenu::instance_ = nullptr;
// Inicializa la instancia única del singleton
void ServiceMenu::init() { ServiceMenu::instance_ = new ServiceMenu(); }
// Libera la instancia
void ServiceMenu::destroy() { delete ServiceMenu::instance_; }
// Obtiene la instancia
ServiceMenu *ServiceMenu::get() { return ServiceMenu::instance_; }
// Constructor
ServiceMenu::ServiceMenu() {
// Inicializa los valores por defecto del menú de servicio
is_active = false;

View File

@@ -6,15 +6,10 @@
class ServiceMenu
{
public:
static ServiceMenu &get_instance()
{
static ServiceMenu instance;
return instance;
}
// Eliminar copia y asignación
ServiceMenu(const ServiceMenu &) = delete;
ServiceMenu &operator=(const ServiceMenu &) = delete;
// --- Métodos de singleton ---
static void init(); // Inicializa el objeto ServiceMenu
static void destroy(); // Libera el objeto ServiceMenu
static ServiceMenu *get(); // Obtiene el puntero al objeto ServiceMenu
void show();
void render();
@@ -22,9 +17,16 @@ public:
void execute_option(size_t option);
private:
ServiceMenu();
~ServiceMenu() = default;
// --- Patrón Singleton ---
ServiceMenu(); // Constructor privado
~ServiceMenu() = default; // Destructor privado
ServiceMenu(const ServiceMenu &) = delete; // Evitar copia
ServiceMenu &operator=(const ServiceMenu &) = delete; // Evitar asignación
// --- Singleton ---
static ServiceMenu *instance_;
// -- Variables internas ---
bool is_active;
size_t selected_option;
std::vector<std::string> options;

View File

@@ -131,7 +131,7 @@ void Tabe::setRandomFlyPath(TabeDirection direction, int lenght)
direction_ = direction;
fly_distance_ = lenght;
waiting_counter_ = 5 + rand() % 15;
Audio::get().playSound("tabe.wav");
Audio::get()->playSound("tabe.wav");
constexpr float SPEED = 2.0f;

View File

@@ -55,7 +55,7 @@ Title::Title()
Title::~Title()
{
Resource::get()->getTexture("smb2.gif")->setPalette(0);
Audio::get().stopAllSounds();
Audio::get()->stopAllSounds();
}
// Actualiza las variables del objeto
@@ -200,8 +200,8 @@ void Title::checkInput()
{
if ((state_ == TitleState::LOGO_FINISHED || ALLOW_TITLE_ANIMATION_SKIP) && !fade_->isEnabled())
{
Audio::get().playSound("game_start.wav");
Audio::get().fadeOutMusic(1500);
Audio::get()->playSound("game_start.wav");
Audio::get()->fadeOutMusic(1500);
switch (CONTROLLER.player_id)
{
case 1:
@@ -322,7 +322,7 @@ void Title::updateFade()
// Se ha pulsado para jugar
section::name = section::Name::GAME;
section::options = selection_;
Audio::get().stopMusic();
Audio::get()->stopMusic();
}
}
}
@@ -339,7 +339,7 @@ void Title::updateState()
if (game_logo_->hasFinished())
{
state_ = TitleState::LOGO_FINISHED;
Audio::get().playMusic("title.ogg");
Audio::get()->playMusic("title.ogg");
}
break;
}