Compare commits

8 Commits

24 changed files with 247 additions and 75 deletions

View File

@@ -30,7 +30,9 @@ Les tecles son les següents:
- **Tecla F5**: Activa o desactiva l'audio - **Tecla F5**: Activa o desactiva l'audio
- **Tecla F6**: Canvia el idioma del joc i reinicia - **Tecla F6**: Activa o desactiva el dispar automàtic
- **Tecla F7**: Canvia el idioma del joc i reinicia
- **Tecla F10**: Reset - **Tecla F10**: Reset

BIN
data/sound/voice_coffee.wav Normal file

Binary file not shown.

BIN
data/sound/voice_no.wav Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -5,6 +5,8 @@
#include "param.h" // Para Param, param, ParamBalloon, ParamGame #include "param.h" // Para Param, param, ParamBalloon, ParamGame
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "resource.h"
#include "jail_audio.h"
// Constructor // Constructor
Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel_x, float speed, Uint16 creation_timer, SDL_Rect play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation) Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel_x, float speed, Uint16 creation_timer, SDL_Rect play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation)
@@ -36,6 +38,7 @@ Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel
power_ = BALLOON_POWER[index]; power_ = BALLOON_POWER[index];
menace_ = BALLOON_MENACE[index]; menace_ = BALLOON_MENACE[index];
score_ = BALLOON_SCORE[index]; score_ = BALLOON_SCORE[index];
sound_ = BALLOON_SOUND[index];
break; break;
} }
@@ -50,14 +53,16 @@ Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel
power_ = BALLOON_POWER[index]; power_ = BALLOON_POWER[index];
menace_ = BALLOON_MENACE[index]; menace_ = BALLOON_MENACE[index];
score_ = BALLOON_SCORE[index]; score_ = BALLOON_SCORE[index];
sound_ = BALLOON_SOUND[index];
break; break;
} }
case BalloonType::POWERBALL: case BalloonType::POWERBALL:
{ {
const int index = 3; constexpr int index = 3;
h_ = w_ = BALLOON_SIZE[4]; h_ = w_ = BALLOON_SIZE[4];
sound_ = BALLOON_SOUND[3];
power_ = score_ = menace_ = 0; power_ = score_ = menace_ = 0;
vy_ = 0; vy_ = 0;
@@ -145,6 +150,7 @@ void Balloon::move()
const float max_x = play_area_.x + play_area_.w - w_ + clip; const float max_x = play_area_.x + play_area_.w - w_ + clip;
if (x_ < min_x || x_ > max_x) if (x_ < min_x || x_ > max_x)
{ {
playSound();
x_ = std::clamp(x_, min_x, max_x); x_ = std::clamp(x_, min_x, max_x);
vx_ = -vx_; vx_ = -vx_;
// Activa el efecto de rebote o invierte la rotación // Activa el efecto de rebote o invierte la rotación
@@ -179,6 +185,7 @@ void Balloon::move()
const int min_y = play_area_.y; const int min_y = play_area_.y;
if (y_ < min_y) if (y_ < min_y)
{ {
playSound();
y_ = min_y; y_ = min_y;
vy_ = -vy_; vy_ = -vy_;
enableBounce(); enableBounce();
@@ -189,6 +196,7 @@ void Balloon::move()
const int max_y = play_area_.y + play_area_.h - h_; const int max_y = play_area_.y + play_area_.h - h_;
if (y_ > max_y) if (y_ > max_y)
{ {
playSound();
y_ = max_y; y_ = max_y;
vy_ = -default_vy_; vy_ = -default_vy_;
if (type_ != BalloonType::POWERBALL) if (type_ != BalloonType::POWERBALL)
@@ -402,3 +410,12 @@ void Balloon::useNormalColor()
use_reversed_colors_ = false; use_reversed_colors_ = false;
setAnimation(); setAnimation();
} }
// Reproduce el sonido al rebotar
void Balloon::playSound()
{
if (sound_enabled_)
{
JA_PlaySound(Resource::get()->getSound(sound_));
}
}

View File

@@ -17,6 +17,7 @@ constexpr int BALLOON_SCORE[] = {50, 100, 200, 400};
constexpr int BALLOON_POWER[] = {1, 3, 7, 15}; constexpr int BALLOON_POWER[] = {1, 3, 7, 15};
constexpr int BALLOON_MENACE[] = {1, 2, 4, 8}; constexpr int BALLOON_MENACE[] = {1, 2, 4, 8};
constexpr int BALLOON_SIZE[] = {10, 16, 26, 48, 49}; constexpr int BALLOON_SIZE[] = {10, 16, 26, 48, 49};
const std::string BALLOON_SOUND[] = {"bubble1.wav", "bubble2.wav", "bubble3.wav", "bubble4.wav"};
// Tamaños de globo // Tamaños de globo
enum class BalloonSize : Uint8 enum class BalloonSize : Uint8
@@ -113,6 +114,8 @@ private:
float speed_; // Velocidad a la que se mueven los globos float speed_; // Velocidad a la que se mueven los globos
Uint8 power_; // Cantidad de poder que alberga el globo Uint8 power_; // Cantidad de poder que alberga el globo
SDL_Rect play_area_; // Zona por donde se puede mover el globo SDL_Rect play_area_; // Zona por donde se puede mover el globo
std::string sound_; // Archivo de sonido que hace el globo al rebotar
bool sound_enabled_ = false; // Indica si ha de sonar el sonido del globo al rebotar
// Alinea el circulo de colisión con la posición del objeto globo // Alinea el circulo de colisión con la posición del objeto globo
void shiftColliders(); void shiftColliders();
@@ -138,6 +141,9 @@ private:
// Establece la animación correspondiente // Establece la animación correspondiente
void setAnimation(); void setAnimation();
// Reproduce el sonido al rebotar
void playSound();
public: public:
// Constructor // Constructor
Balloon( Balloon(
@@ -208,4 +214,5 @@ public:
void setVelY(float vel_y) { vy_ = vel_y; } void setVelY(float vel_y) { vy_ = vel_y; }
void setSpeed(float speed) { speed_ = speed; } void setSpeed(float speed) { speed_ = speed; }
void setInvulnerable(bool value) { invulnerable_ = value; } void setInvulnerable(bool value) { invulnerable_ = value; }
void setSound(bool value) { sound_enabled_ = value; }
}; };

View File

@@ -372,3 +372,12 @@ int BalloonManager::getMenace()
return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon) return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon)
{ return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); }); { return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); });
} }
// Establece el sonido de los globos
void BalloonManager::setSounds(bool value)
{
for (auto &balloon : balloons_)
{
balloon->setSound(value);
}
}

View File

@@ -111,6 +111,9 @@ public:
// Obtiene el nivel de ameza actual generado por los globos // Obtiene el nivel de ameza actual generado por los globos
int getMenace(); int getMenace();
// Establece el sonido de los globos
void setSounds(bool value);
// Getters // Getters
float getBalloonSpeed() const { return balloon_speed_; } float getBalloonSpeed() const { return balloon_speed_; }
Balloons &getBalloons() { return balloons_; } Balloons &getBalloons() { return balloons_; }

View File

@@ -180,8 +180,9 @@ void Director::bindInputs()
Input::get()->bindKey(InputType::WINDOW_FULLSCREEN, SDL_SCANCODE_F3); Input::get()->bindKey(InputType::WINDOW_FULLSCREEN, SDL_SCANCODE_F3);
Input::get()->bindKey(InputType::VIDEO_SHADERS, SDL_SCANCODE_F4); Input::get()->bindKey(InputType::VIDEO_SHADERS, SDL_SCANCODE_F4);
Input::get()->bindKey(InputType::MUTE, SDL_SCANCODE_F5); Input::get()->bindKey(InputType::MUTE, SDL_SCANCODE_F5);
Input::get()->bindKey(InputType::CHANGE_LANG, SDL_SCANCODE_F6); Input::get()->bindKey(InputType::AUTO_FIRE, SDL_SCANCODE_F6);
Input::get()->bindKey(InputType::SHOWINFO, SDL_SCANCODE_F7); Input::get()->bindKey(InputType::CHANGE_LANG, SDL_SCANCODE_F7);
Input::get()->bindKey(InputType::SHOWINFO, SDL_SCANCODE_F8);
Input::get()->bindKey(InputType::RESET, SDL_SCANCODE_F10); Input::get()->bindKey(InputType::RESET, SDL_SCANCODE_F10);
// Asigna botones a inputs // Asigna botones a inputs
@@ -295,8 +296,15 @@ bool Director::initSDL()
} }
*/ */
// Obtiene información sobre la pantalla
SDL_DisplayMode DM; SDL_DisplayMode DM;
SDL_GetCurrentDisplayMode(0, &DM); SDL_GetCurrentDisplayMode(0, &DM);
// Calcula el máximo factor de zoom que se puede aplicar a la pantalla
options.video.window.max_size = std::min(DM.w / param.game.width, DM.h / param.game.height);
options.video.window.size = std::min(options.video.window.size, options.video.window.max_size);
// Muestra información sobre el tamaño de la pantalla y de la ventana de juego
std::cout << "\nCurrent display mode: " << DM.w << "x" << DM.h << " @ " << DM.refresh_rate << "Hz" << std::endl; std::cout << "\nCurrent display mode: " << DM.w << "x" << DM.h << " @ " << DM.refresh_rate << "Hz" << std::endl;
std::cout << "Window resolution : " << param.game.width << "x" << param.game.height << " x" << options.video.window.size << std::endl; std::cout << "Window resolution : " << param.game.width << "x" << param.game.height << " x" << options.video.window.size << std::endl;
@@ -397,6 +405,9 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/sound/powerball.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/powerball.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/notify.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/notify.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/logo.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/logo.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_coffee.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_power_up.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_no.wav", AssetType::SOUND);
// Shaders // Shaders
Asset::get()->add(prefix + "/data/shaders/crtpi_256.glsl", AssetType::DATA); Asset::get()->add(prefix + "/data/shaders/crtpi_256.glsl", AssetType::DATA);

View File

@@ -100,6 +100,8 @@ void Fade::update()
SDL_RenderFillRect(renderer_, &rect1_); SDL_RenderFillRect(renderer_, &rect1_);
SDL_RenderFillRect(renderer_, &rect2_); SDL_RenderFillRect(renderer_, &rect2_);
value_ = calculateValue(0, counter_, i);
} }
// Deja el renderizador como estaba // Deja el renderizador como estaba
@@ -139,6 +141,8 @@ void Fade::update()
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
} }
value_ = calculateValue(0, static_cast<int>(num_squares_width_ * num_squares_height_), static_cast<int>(counter_ * fade_random_squares_mult_ / fade_random_squares_delay_));
// Comprueba si ha terminado // Comprueba si ha terminado
if (counter_ * fade_random_squares_mult_ / fade_random_squares_delay_ >= num_squares_width_ * num_squares_height_) if (counter_ * fade_random_squares_mult_ / fade_random_squares_delay_ >= num_squares_width_ * num_squares_height_)
{ {
@@ -338,3 +342,11 @@ void Fade::cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
// Vuelve a dejar el renderizador como estaba // Vuelve a dejar el renderizador como estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
} }
// Calcula el valor del estado del fade
int Fade::calculateValue(int min, int max, int current)
{
if (max == 0)
return 0;
return std::clamp(current * 100 / max, 0, 100);
}

View File

@@ -45,6 +45,7 @@ private:
int fade_random_squares_mult_; // Cantidad de cuadrados que se pintaran cada vez int fade_random_squares_mult_; // Cantidad de cuadrados que se pintaran cada vez
int post_duration_; // Duración posterior del fade tras finalizar int post_duration_; // Duración posterior del fade tras finalizar
int post_counter_; // Contador para la duración posterior int post_counter_; // Contador para la duración posterior
int value_ = 0; // Estado actual del fade entre 0 y 100
// Inicializa las variables // Inicializa las variables
void init(); void init();
@@ -52,6 +53,9 @@ private:
// Limpia el backbuffer // Limpia el backbuffer
void cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a); void cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
// Calcula el valor del estado del fade
int calculateValue(int min, int max, int current);
public: public:
// Constructor // Constructor
Fade(); Fade();
@@ -88,4 +92,7 @@ public:
// Establece la duración posterior // Establece la duración posterior
void setPost(int value); void setPost(int value);
// Getters
int getValue() const { return value_; }
}; };

View File

@@ -44,7 +44,8 @@ Game::Game(int player_id, int current_stage, bool demo)
input_(Input::get()), input_(Input::get()),
background_(std::make_unique<Background>()), background_(std::make_unique<Background>()),
canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.play_area.rect.w, param.game.play_area.rect.h)), canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.play_area.rect.w, param.game.play_area.rect.h)),
fade_(std::make_unique<Fade>()), fade_in_(std::make_unique<Fade>()),
fade_out_(std::make_unique<Fade>()),
balloon_manager_(std::make_unique<BalloonManager>()) balloon_manager_(std::make_unique<BalloonManager>())
{ {
// Pasa variables // Pasa variables
@@ -63,9 +64,15 @@ Game::Game(int player_id, int current_stage, bool demo)
Scoreboard::init(); Scoreboard::init();
scoreboard_ = Scoreboard::get(); scoreboard_ = Scoreboard::get();
fade_->setColor(fade_color.r, fade_color.g, fade_color.b); fade_in_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_->setPost(param.fade.post_duration); fade_in_->setPost(param.fade.post_duration);
fade_->setType(FadeType::VENETIAN); fade_in_->setType(FadeType::RANDOM_SQUARE);
fade_in_->setMode(FadeMode::IN);
fade_in_->activate();
fade_out_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_out_->setPost(param.fade.post_duration);
fade_out_->setType(FadeType::VENETIAN);
background_->setPos(param.game.play_area.rect); background_->setPos(param.game.play_area.rect);
@@ -213,8 +220,8 @@ void Game::updatePlayers()
if (demo_.enabled && allPlayersAreNotPlaying()) if (demo_.enabled && allPlayersAreNotPlaying())
{ {
fade_->setType(FadeType::RANDOM_SQUARE); fade_out_->setType(FadeType::RANDOM_SQUARE);
fade_->activate(); fade_out_->activate();
} }
} }
@@ -283,25 +290,21 @@ void Game::updateGameOverState()
if (game_over_counter_ > 0) if (game_over_counter_ > 0)
{ {
if (game_over_counter_ == GAME_OVER_COUNTER_) if (game_over_counter_ == GAME_OVER_COUNTER_)
{
createMessage({paths_.at(2), paths_.at(3)}, Resource::get()->getTexture("game_over")); createMessage({paths_.at(2), paths_.at(3)}, Resource::get()->getTexture("game_over"));
stopMusic();
balloon_manager_->setSounds(true);
}
game_over_counter_--; game_over_counter_--;
if ((game_over_counter_ == 250) || (game_over_counter_ == 200) || (game_over_counter_ == 180) || (game_over_counter_ == 120) || (game_over_counter_ == 60))
{
// Hace sonar aleatoriamente uno de los 4 sonidos de burbujas
const auto index = rand() % 4;
JA_Sound_t *sound[4] = {Resource::get()->getSound("bubble1.wav"), Resource::get()->getSound("bubble2.wav"), Resource::get()->getSound("bubble3.wav"), Resource::get()->getSound("bubble4.wav")};
JA_PlaySound(sound[index], 0);
}
if (game_over_counter_ == 150) if (game_over_counter_ == 150)
{ {
fade_->activate(); fade_out_->activate();
} }
} }
if (fade_->hasEnded()) if (fade_out_->hasEnded())
{ {
if (game_completed_counter_ > 0) if (game_completed_counter_ > 0)
{ {
@@ -474,6 +477,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
(item->getWidth() - game_text_textures_[4]->getWidth()) / 2; (item->getWidth() - game_text_textures_[4]->getWidth()) / 2;
createItemText(x, game_text_textures_[4]); createItemText(x, game_text_textures_[4]);
} }
JA_PlaySound(Resource::get()->getSound("voice_coffee.wav"));
break; break;
} }
case ItemType::COFFEE_MACHINE: case ItemType::COFFEE_MACHINE:
@@ -484,6 +488,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
item->getPosX() + item->getPosX() +
(item->getWidth() - game_text_textures_[3]->getWidth()) / 2; (item->getWidth() - game_text_textures_[3]->getWidth()) / 2;
createItemText(x, game_text_textures_[3]); createItemText(x, game_text_textures_[3]);
JA_PlaySound(Resource::get()->getSound("voice_power_up.wav"));
break; break;
} }
default: default:
@@ -722,7 +727,9 @@ void Game::createMessage(const std::vector<Path> &paths, std::shared_ptr<Texture
// Inicializa // Inicializa
for (const auto &path : paths) for (const auto &path : paths)
{
path_sprites_.back()->addPath(path, true); path_sprites_.back()->addPath(path, true);
}
path_sprites_.back()->enable(); path_sprites_.back()->enable();
} }
@@ -815,13 +822,13 @@ void Game::killPlayer(std::shared_ptr<Player> &player)
else else
{ {
// Si no tiene cafes, muere // Si no tiene cafes, muere
pauseMusic(); // pauseMusic();
balloon_manager_->stopAllBalloons(); balloon_manager_->stopAllBalloons();
JA_PlaySound(Resource::get()->getSound("player_collision.wav")); JA_PlaySound(Resource::get()->getSound("player_collision.wav"));
screen_->shake(); screen_->shake();
JA_PlaySound(Resource::get()->getSound("coffeeout.wav")); JA_PlaySound(Resource::get()->getSound("voice_no.wav"));
player->setPlayingState(PlayerState::DYING); player->setPlayingState(PlayerState::DYING);
allPlayersAreNotPlaying() ? stopMusic() : resumeMusic(); // allPlayersAreNotPlaying() ? stopMusic() : resumeMusic();
} }
} }
@@ -869,7 +876,7 @@ void Game::update()
checkMusicStatus(); checkMusicStatus();
screen_->update(); screen_->update();
globalInputs::update(); globalInputs::update();
fillCanvas(); fillCanvas();
} }
} }
@@ -935,7 +942,8 @@ void Game::render()
scoreboard_->render(); scoreboard_->render();
// Dibuja el fade // Dibuja el fade
fade_->render(); fade_in_->render();
fade_out_->render();
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
screen_->blit(); screen_->blit();
@@ -960,10 +968,8 @@ void Game::disableTimeStopItem()
// Comprueba si la música ha de estar sonando // Comprueba si la música ha de estar sonando
void Game::checkMusicStatus() void Game::checkMusicStatus()
{ {
// Si la música no está sonando // Si se ha completado el juego o los jugadores han terminado, detiene la música
if (JA_GetMusicState() == JA_MUSIC_INVALID || JA_GetMusicState() == JA_MUSIC_STOPPED) state_ == GameState::COMPLETED || allPlayersAreGameOver() ? stopMusic() : playMusic();
// Si se ha completado el juego o los jugadores han terminado, detiene la música
state_ == GameState::COMPLETED || allPlayersAreGameOver() ? JA_StopMusic() : JA_PlayMusic(Resource::get()->getMusic("playing.ogg"));
} }
// Bucle para el juego // Bucle para el juego
@@ -998,8 +1004,7 @@ void Game::initPaths()
paths_.emplace_back(Path(createPath(x1, x2, PathType::HORIZONTAL, y, 80, easeInQuint), 0)); paths_.emplace_back(Path(createPath(x1, x2, PathType::HORIZONTAL, y, 80, easeInQuint), 0));
} }
// Recorrido para el texto de "Last Stage!" o de "X stages left" o "Game Over" // Recorrido para el texto de "Last Stage!" o de "X stages left" o "Game Over" (2,3)
// (2,3)
{ {
const auto &texture = Resource::get()->getTexture("last_stage"); const auto &texture = Resource::get()->getTexture("last_stage");
const auto h = texture->getHeight(); const auto h = texture->getHeight();
@@ -1691,6 +1696,16 @@ void Game::resumeMusic()
} }
} }
// Hace sonar la música
void Game::playMusic()
{
// Si la música no está sonando
if (JA_GetMusicState() == JA_MUSIC_INVALID || JA_GetMusicState() == JA_MUSIC_STOPPED)
{
JA_PlayMusic(Resource::get()->getMusic("playing.ogg"));
}
}
// Detiene la música // Detiene la música
void Game::stopMusic() void Game::stopMusic()
{ {
@@ -1712,12 +1727,12 @@ void Game::updateDemo()
// Activa el fundido antes de acabar con los datos de la demo // Activa el fundido antes de acabar con los datos de la demo
if (demo_.counter == TOTAL_DEMO_DATA - 200) if (demo_.counter == TOTAL_DEMO_DATA - 200)
{ {
fade_->setType(FadeType::RANDOM_SQUARE); fade_out_->setType(FadeType::RANDOM_SQUARE);
fade_->activate(); fade_out_->activate();
} }
// Si ha terminado el fundido, cambia de sección // Si ha terminado el fundido, cambia de sección
if (fade_->hasEnded()) if (fade_out_->hasEnded())
{ {
section::name = section::Name::HI_SCORE_TABLE; section::name = section::Name::HI_SCORE_TABLE;
return; return;
@@ -1756,7 +1771,8 @@ void Game::updateGame()
Stage::addPower(5); Stage::addPower(5);
} }
#endif #endif
fade_->update(); fade_in_->update();
fade_out_->update();
updatePlayers(); updatePlayers();
checkPlayersStatusPlaying(); checkPlayersStatusPlaying();
updateScoreboard(); updateScoreboard();

View File

@@ -140,7 +140,8 @@ private:
std::vector<std::vector<std::string>> item_animations_; // Vector con las animaciones de los items std::vector<std::vector<std::string>> item_animations_; // Vector con las animaciones de los items
std::vector<std::vector<std::string>> player_animations_; // Vector con las animaciones del jugador std::vector<std::vector<std::string>> player_animations_; // Vector con las animaciones del jugador
std::unique_ptr<Fade> fade_; // Objeto para renderizar fades std::unique_ptr<Fade> fade_in_; // Objeto para renderizar fades
std::unique_ptr<Fade> fade_out_; // Objeto para renderizar fades
std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos
std::vector<Path> paths_; // Vector con los recorridos precalculados almacenados std::vector<Path> paths_; // Vector con los recorridos precalculados almacenados
@@ -373,6 +374,9 @@ private:
// Reanuda la música // Reanuda la música
void resumeMusic(); void resumeMusic();
// Hace sonar la música
void playMusic();
// Detiene la música // Detiene la música
void stopMusic(); void stopMusic();

View File

@@ -1,4 +1,5 @@
#include "game_logo.h" #include "game_logo.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL #include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL
#include <algorithm> // Para max #include <algorithm> // Para max
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
@@ -8,6 +9,11 @@
#include "smart_sprite.h" // Para SmartSprite #include "smart_sprite.h" // Para SmartSprite
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "screen.h"
constexpr int ZOOM_FACTOR = 5;
constexpr int FLASH_DELAY = 3;
constexpr int FLASH_LENGHT = FLASH_DELAY + 3;
// Constructor // Constructor
GameLogo::GameLogo(int x, int y) GameLogo::GameLogo(int x, int y)
@@ -21,7 +27,7 @@ GameLogo::GameLogo(int x, int y)
crisis_sprite_(std::make_unique<SmartSprite>(crisis_texture_)), crisis_sprite_(std::make_unique<SmartSprite>(crisis_texture_)),
arcade_edition_sprite_(std::make_unique<Sprite>(arcade_edition_texture_, (param.game.width - arcade_edition_texture_->getWidth()) / 2, param.title.arcade_edition_position, arcade_edition_texture_->getWidth(), arcade_edition_texture_->getHeight())), arcade_edition_sprite_(std::make_unique<Sprite>(arcade_edition_texture_, (param.game.width - arcade_edition_texture_->getWidth()) / 2, param.title.arcade_edition_position, arcade_edition_texture_->getWidth(), arcade_edition_texture_->getHeight())),
x_(x), x_(x),
y_(y) { } y_(y) {}
// Inicializa las variables // Inicializa las variables
void GameLogo::init() void GameLogo::init()
@@ -32,15 +38,8 @@ void GameLogo::init()
// Variables // Variables
coffee_crisis_status_ = Status::DISABLED; coffee_crisis_status_ = Status::DISABLED;
arcade_edition_status_ = Status::DISABLED; arcade_edition_status_ = Status::DISABLED;
shake_.init(1, 2, 8, xp);
shake_.desp = 1; zoom_ = 3.0f * ZOOM_FACTOR;
shake_.delay = 2;
shake_.lenght = 8;
shake_.remaining = shake_.lenght;
shake_.counter = shake_.delay;
shake_.origin = xp;
zoom_ = 3.0f;
// Inicializa el bitmap de 'Coffee' // Inicializa el bitmap de 'Coffee'
coffee_sprite_->setPosX(xp); coffee_sprite_->setPosX(xp);
@@ -122,10 +121,11 @@ void GameLogo::update()
if (coffee_sprite_->hasFinished() && crisis_sprite_->hasFinished()) if (coffee_sprite_->hasFinished() && crisis_sprite_->hasFinished())
{ {
coffee_crisis_status_ = Status::SHAKING; coffee_crisis_status_ = Status::SHAKING;
arcade_edition_status_ = Status::MOVING;
// Reproduce el efecto sonoro // Reproduce el efecto sonoro
JA_PlaySound(Resource::get()->getSound("title.wav")); JA_PlaySound(Resource::get()->getSound("title.wav"));
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGHT, FLASH_DELAY);
Screen::get()->shake();
} }
break; break;
@@ -133,7 +133,7 @@ void GameLogo::update()
case Status::SHAKING: case Status::SHAKING:
{ {
// Agita el logo // Agita "COFFEE CRISIS"
if (shake_.remaining > 0) if (shake_.remaining > 0)
{ {
if (shake_.counter > 0) if (shake_.counter > 0)
@@ -154,6 +154,7 @@ void GameLogo::update()
coffee_sprite_->setPosX(shake_.origin); coffee_sprite_->setPosX(shake_.origin);
crisis_sprite_->setPosX(shake_.origin + 15); crisis_sprite_->setPosX(shake_.origin + 15);
coffee_crisis_status_ = Status::FINISHED; coffee_crisis_status_ = Status::FINISHED;
arcade_edition_status_ = Status::MOVING;
} }
dust_right_sprite_->update(); dust_right_sprite_->update();
@@ -178,12 +179,42 @@ void GameLogo::update()
{ {
case Status::MOVING: case Status::MOVING:
{ {
zoom_ -= 0.1f; zoom_ -= 0.1f * ZOOM_FACTOR;
arcade_edition_sprite_->setZoom(zoom_); arcade_edition_sprite_->setZoom(zoom_);
if (zoom_ <= 1.0f) if (zoom_ <= 1.0f)
{ {
arcade_edition_status_ = Status::FINISHED; arcade_edition_status_ = Status::SHAKING;
zoom_ = 1.0f; zoom_ = 1.0f;
arcade_edition_sprite_->setZoom(zoom_);
shake_.init(1, 2, 8, arcade_edition_sprite_->getX());
JA_PlaySound(Resource::get()->getSound("title.wav"));
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGHT, FLASH_DELAY);
Screen::get()->shake();
}
break;
}
case Status::SHAKING:
{
// Agita "ARCADE EDITION"
if (shake_.remaining > 0)
{
if (shake_.counter > 0)
{
shake_.counter--;
}
else
{
shake_.counter = shake_.delay;
const auto desp = shake_.remaining % 2 == 0 ? shake_.desp * (-1) : shake_.desp;
arcade_edition_sprite_->setX(shake_.origin + desp);
shake_.remaining--;
}
}
else
{
arcade_edition_sprite_->setX(shake_.origin);
arcade_edition_status_ = Status::FINISHED;
} }
break; break;
} }
@@ -191,6 +222,13 @@ void GameLogo::update()
default: default:
break; break;
} }
if (coffee_crisis_status_ == Status::FINISHED &&
arcade_edition_status_ == Status::FINISHED &&
post_finished_counter_ > 0)
{
--post_finished_counter_;
}
} }
// Activa la clase // Activa la clase
@@ -203,7 +241,7 @@ void GameLogo::enable()
// Indica si ha terminado la animación // Indica si ha terminado la animación
bool GameLogo::hasFinished() const bool GameLogo::hasFinished() const
{ {
return coffee_crisis_status_ == Status::FINISHED && arcade_edition_status_ == Status::FINISHED; return post_finished_counter_ == 0;
} }
// Recarga las texturas // Recarga las texturas

View File

@@ -20,12 +20,30 @@ private:
struct Shake struct Shake
{ {
int desp; // Pixels de desplazamiento para agitar la pantalla en el eje x int desp = 1; // Pixels de desplazamiento para agitar la pantalla en el eje x
int delay; // Retraso entre cada desplazamiento de la pantalla al agitarse int delay = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse
int counter; // Contador para el retraso int lenght = 8; // Cantidad de desplazamientos a realizar
int lenght; // Cantidad de desplazamientos a realizar int remaining = lenght; // Cantidad de desplazamientos pendientes a realizar
int remaining; // Cantidad de desplazamientos pendientes a realizar int counter = delay; // Contador para el retraso
int origin; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento int origin; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
// Constructor por defect
Shake() = default;
// Constructor
Shake(int d, int de, int l, int o)
: desp(d), delay(de), lenght(l), remaining(l), counter(de), origin(o) {}
// Inicializa los miembros
void init(int d, int de, int l, int o)
{
desp = d;
delay = de;
lenght = l;
remaining = l;
counter = de;
origin = o;
}
}; };
// Objetos y punteros // Objetos y punteros
@@ -43,9 +61,10 @@ private:
std::unique_ptr<Sprite> arcade_edition_sprite_; // Sprite con los graficos de "Arcade Edition" std::unique_ptr<Sprite> arcade_edition_sprite_; // Sprite con los graficos de "Arcade Edition"
// Variables // Variables
int x_; // Posición donde dibujar el logo int x_; // Posición donde dibujar el logo
int y_; // Posición donde dibujar el logo int y_; // Posición donde dibujar el logo
float zoom_; // Zoom aplicado al texto "ARCADE EDITION" float zoom_; // Zoom aplicado al texto "ARCADE EDITION"
int post_finished_counter_ = 1; // Contador final una vez terminada las animaciones de los logos
Status coffee_crisis_status_ = Status::DISABLED; // Estado en el que se encuentra el texto "COFFEE CRISIS" Status coffee_crisis_status_ = Status::DISABLED; // Estado en el que se encuentra el texto "COFFEE CRISIS"
Status arcade_edition_status_ = Status::DISABLED; // Estado en el que se encuentra el texto "ARCADE_EDITION" Status arcade_edition_status_ = Status::DISABLED; // Estado en el que se encuentra el texto "ARCADE_EDITION"

View File

@@ -108,6 +108,13 @@ namespace globalInputs
Notifier::get()->showText({getLangName(options.game.language)}); Notifier::get()->showText({getLangName(options.game.language)});
} }
// Cambia el modo de disparo
void toggleFireMode()
{
options.game.autofire = !options.game.autofire;
Notifier::get()->showText({"Autofire " + boolToOnOff(options.game.autofire)});
}
// Comprueba los inputs que se pueden introducir en cualquier sección del juego // Comprueba los inputs que se pueden introducir en cualquier sección del juego
void check() void check()
{ {
@@ -162,6 +169,13 @@ namespace globalInputs
return; return;
} }
// Autofire
if (Input::get()->checkInput(InputType::AUTO_FIRE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
{
toggleFireMode();
return;
}
// Idioma // Idioma
if (Input::get()->checkInput(InputType::CHANGE_LANG, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) if (Input::get()->checkInput(InputType::CHANGE_LANG, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
{ {

View File

@@ -44,6 +44,7 @@ enum class InputType : int
SHOWINFO, SHOWINFO,
CONFIG, CONFIG,
SWAP_CONTROLLERS, SWAP_CONTROLLERS,
AUTO_FIRE,
// Input obligatorio // Input obligatorio
NONE, NONE,

View File

@@ -59,7 +59,7 @@ Logo::~Logo()
{ {
jail_texture_->setColor(255, 255, 255); jail_texture_->setColor(255, 255, 255);
since_texture_->setColor(255, 255, 255); since_texture_->setColor(255, 255, 255);
JA_PauseChannel(-1); JA_StopChannel(-1);
} }
// Recarga todas las texturas // Recarga todas las texturas
@@ -101,7 +101,6 @@ void Logo::checkInput()
// Comprueba si se ha pulsado cualquier botón (de los usados para jugar) // Comprueba si se ha pulsado cualquier botón (de los usados para jugar)
if (Input::get()->checkAnyButtonPressed()) if (Input::get()->checkAnyButtonPressed())
{ {
JA_StopMusic();
section::name = section::Name::TITLE; section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1; section::options = section::Options::TITLE_1;
return; return;

View File

@@ -23,7 +23,8 @@ enum class GameDifficulty
// Estructura para las opciones de la ventana // Estructura para las opciones de la ventana
struct OptionsWindow struct OptionsWindow
{ {
int size; // Contiene el valor por el que se multiplica el tamaño de la ventana int size = 1; // Contiene el valor por el que se multiplica el tamaño de la ventana
int max_size = 1; // Tamaño máximo para que el tamaño de la ventana no sea mayor que el tamaño de la pantalla
}; };
// Estructura con opciones para el video // Estructura con opciones para el video

View File

@@ -8,6 +8,8 @@
#include "param.h" // Para Param, ParamGame, param #include "param.h" // Para Param, ParamGame, param
#include "scoreboard.h" // Para Scoreboard, ScoreboardMode #include "scoreboard.h" // Para Scoreboard, ScoreboardMode
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "resource.h"
#include "jail_audio.h"
// Constructor // Constructor
Player::Player(int id, float x, int y, bool demo, SDL_Rect &play_area, std::vector<std::shared_ptr<Texture>> texture, const std::vector<std::vector<std::string>> &animations) Player::Player(int id, float x, int y, bool demo, SDL_Rect &play_area, std::vector<std::shared_ptr<Texture>> texture, const std::vector<std::vector<std::string>> &animations)
@@ -175,6 +177,7 @@ void Player::move()
if ((player_sprite_->getPosX() < play_area_.x) || (player_sprite_->getPosX() + WIDTH_ > play_area_.w)) if ((player_sprite_->getPosX() < play_area_.x) || (player_sprite_->getPosX() + WIDTH_ > play_area_.w))
{ {
player_sprite_->setVelX(-player_sprite_->getVelX()); player_sprite_->setVelX(-player_sprite_->getVelX());
JA_PlaySound(Resource::get()->getSound("bubble4.wav"));
} }
// Si el cadaver toca el suelo cambia el estado // Si el cadaver toca el suelo cambia el estado
@@ -188,6 +191,7 @@ void Player::move()
pos_y_ = default_pos_y_; pos_y_ = default_pos_y_;
player_sprite_->clear(); player_sprite_->clear();
shiftSprite(); shiftSprite();
JA_PlaySound(Resource::get()->getSound("bubble4.wav"));
} }
else else
{ {
@@ -195,6 +199,7 @@ void Player::move()
player_sprite_->setPosY(play_area_.h - HEIGHT_); player_sprite_->setPosY(play_area_.h - HEIGHT_);
player_sprite_->setVelY(player_sprite_->getVelY() * -0.5f); player_sprite_->setVelY(player_sprite_->getVelY() * -0.5f);
player_sprite_->setVelX(player_sprite_->getVelX() * 0.75f); player_sprite_->setVelX(player_sprite_->getVelX() * 0.75f);
JA_PlaySound(Resource::get()->getSound("bubble4.wav"));
} }
} }
break; break;

View File

@@ -235,7 +235,7 @@ void Screen::decWindowSize()
void Screen::incWindowSize() void Screen::incWindowSize()
{ {
++options.video.window.size; ++options.video.window.size;
options.video.window.size = std::min(options.video.window.size, 4); options.video.window.size = std::min(options.video.window.size, options.video.window.max_size);
setVideoMode(ScreenVideoMode::WINDOW); setVideoMode(ScreenVideoMode::WINDOW);
} }
@@ -308,15 +308,15 @@ void Screen::updateShakeEffect()
} }
// Pone la pantalla de color // Pone la pantalla de color
void Screen::flash(Color color, int lenght) void Screen::flash(Color color, int lenght, int delay)
{ {
flash_effect_ = FlashEffect(true, lenght, color); flash_effect_ = FlashEffect(true, lenght, delay, color);
} }
// Actualiza y dibuja el efecto de flash en la pantalla // Actualiza y dibuja el efecto de flash en la pantalla
void Screen::renderFlash() void Screen::renderFlash()
{ {
if (flash_effect_.enabled) if (flash_effect_.isRendarable())
{ {
SDL_SetRenderDrawColor(renderer_, flash_effect_.color.r, flash_effect_.color.g, flash_effect_.color.b, 0xFF); SDL_SetRenderDrawColor(renderer_, flash_effect_.color.r, flash_effect_.color.g, flash_effect_.color.b, 0xFF);
SDL_RenderClear(renderer_); SDL_RenderClear(renderer_);
@@ -326,10 +326,7 @@ void Screen::renderFlash()
// Actualiza el efecto de flash // Actualiza el efecto de flash
void Screen::updateFlash() void Screen::updateFlash()
{ {
if (flash_effect_.enabled) flash_effect_.update();
{
flash_effect_.counter > 0 ? flash_effect_.counter-- : flash_effect_.enabled = false;
}
} }
// Atenua la pantalla // Atenua la pantalla

View File

@@ -51,12 +51,20 @@ private:
struct FlashEffect struct FlashEffect
{ {
bool enabled; // Indica si el efecto está activo bool enabled; // Indica si el efecto está activo
int lenght; // Duración del efecto
int delay; // Frames iniciales en los que no se aplica
int counter; // Contador para el efecto int counter; // Contador para el efecto
Color color; // Color del efecto Color color; // Color del efecto
// Constructor // Constructor
explicit FlashEffect(bool en = false, int cnt = 0, Color col = Color(0xFF, 0xFF, 0xFF)) explicit FlashEffect(bool enabled = false, int lenght = 0, int delay = 0, Color color = Color(0xFF, 0xFF, 0xFF))
: enabled(en), counter(cnt), color(col) {} : enabled(enabled), lenght(lenght), delay(delay), counter(lenght), color(color) {}
// Actualiza
void update() { (enabled && counter > 0) ? counter-- : enabled = false; }
// Indica si se pude dibujar
bool isRendarable() { return enabled && counter < lenght - delay; }
}; };
struct ShakeEffect struct ShakeEffect
@@ -155,7 +163,7 @@ public:
void shake(); void shake();
// Pone la pantalla de color // Pone la pantalla de color
void flash(Color color, int lenght); void flash(Color color, int lenght, int delay = 0);
// Activa / desactiva los shaders // Activa / desactiva los shaders
void toggleShaders(); void toggleShaders();

View File

@@ -54,6 +54,7 @@ Title::Title()
Title::~Title() Title::~Title()
{ {
Resource::get()->getTexture("smb2.gif")->setPalette(0); Resource::get()->getTexture("smb2.gif")->setPalette(0);
JA_StopChannel(-1);
} }
// Actualiza las variables del objeto // Actualiza las variables del objeto
@@ -74,6 +75,7 @@ void Title::update()
// Comprueba el fundido y si se ha acabado // Comprueba el fundido y si se ha acabado
fade_->update(); fade_->update();
JA_SetMusicVolume(100 - fade_->getValue());
if (fade_->hasEnded()) if (fade_->hasEnded())
{ {
if (post_fade_ == -1) if (post_fade_ == -1)

View File

@@ -18,7 +18,7 @@ namespace section
constexpr const char TEXT_COPYRIGHT[] = "@2020,2024 JailDesigner"; constexpr const char TEXT_COPYRIGHT[] = "@2020,2024 JailDesigner";
// Parámetros // Parámetros
constexpr bool ALLOW_TITLE_ANIMATION_SKIP = true; constexpr bool ALLOW_TITLE_ANIMATION_SKIP = false;
/* /*
Esta clase gestiona un estado del programa. Se encarga de la parte del titulo o menu Esta clase gestiona un estado del programa. Se encarga de la parte del titulo o menu