Compare commits

14 Commits

Author SHA1 Message Date
e61daeb92e Modificats els grafics del enemic nou
Afegits nous audios i veus
Completat el comportament del enemic nou
Ampliat el numero máxim de sons simultanis
2024-12-28 21:23:04 +01:00
d57cc15aee Treballant en el enemic nou 2024-12-27 13:38:07 +01:00
de3b18a407 Posat ordre en el Attract Mode 2024-12-26 13:58:25 +01:00
7f444fef33 Fix: mil minibugs relacionats amb el audio 2024-12-26 10:39:48 +01:00
ca18baefd7 Fix: el modo demo desactivava els sons i ja no s'activaven mai mes 2024-12-26 10:05:41 +01:00
b8dca0a46f Fet el fade out del title de video i audio i el fade in del joc de video i audio
Actualitzat jail_audio a la última versió
2024-12-26 10:03:02 +01:00
ca2c48ea17 Au, paca casa. M'he quedat a mitjes fent un fade de audio sincronitzat amb el fade de video en el titol 2024-12-23 13:56:11 +01:00
fb4d0d12db Afegits roidets de colisió per als globos per a certs moments 2024-12-23 12:37:19 +01:00
fb31445731 Comprova al iniciar que el tamany de finestra no siga mes gran que el tamany de la pantalla 2024-12-23 11:22:26 +01:00
cf4f0459b3 Es pot fer la finestra tan gran com deixe la pantalla, es a dir, el factor de zoom ja no va de 1 a 4 sino de 1 a X 2024-12-23 11:13:14 +01:00
fe0900a686 Afegides veus al jugador
Afegit efectes de so al rebotar el jugador quan mor
2024-12-15 20:00:35 +01:00
3367b70cd5 Afegit delay opcional al flash de la classe Screen 2024-12-09 20:06:59 +01:00
7016849587 FIX: afegit StopChannel en lloc de PauseChannel en el destructor del Logo
Retocada la animació del logo del joc en Title
2024-12-09 19:08:22 +01:00
301c059a26 Afegit botó per activar o desactivar el autofire 2024-12-05 12:24:18 +01:00
39 changed files with 812 additions and 397 deletions

3
.gitignore vendored
View File

@@ -15,4 +15,5 @@ thumbs.db
*score.bin *score.bin
coffee_crisis* coffee_crisis*
debug.txt debug.txt
cppcheck-result* cppcheck-result*
desktop.ini

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

View File

@@ -14,7 +14,7 @@ fade.num_squares_height 120
fade.random_squares_delay 1 fade.random_squares_delay 1
fade.random_squares_mult 500 fade.random_squares_mult 500
fade.post_duration 80 fade.post_duration 80
fade.venetian_size 16 fade.venetian_size 12
## SCOREBOARD ## SCOREBOARD
scoreboard.x 0 scoreboard.x 0

View File

@@ -14,7 +14,7 @@ fade.num_squares_height 128
fade.random_squares_delay 1 fade.random_squares_delay 1
fade.random_squares_mult 500 fade.random_squares_mult 500
fade.post_duration 80 fade.post_duration 80
fade.venetian_size 16 fade.venetian_size 12
## SCOREBOARD ## SCOREBOARD
scoreboard.x 0 scoreboard.x 0

9
data/gfx/tabe/tabe.ani Normal file
View File

@@ -0,0 +1,9 @@
frame_width=32
frame_height=32
[animation]
name=default
speed=2
loop=0
frames=0,1
[/animation]

BIN
data/gfx/tabe/tabe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
data/sound/game_start.wav Normal file

Binary file not shown.

BIN
data/sound/tabe.wav Normal file

Binary file not shown.

BIN
data/sound/voice_coffee.wav Normal file

Binary file not shown.

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)
@@ -401,4 +409,13 @@ 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

@@ -371,4 +371,13 @@ 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

@@ -54,7 +54,7 @@ Director::Director(int argc, const char *argv[])
section::name = section::Name::GAME; section::name = section::Name::GAME;
section::options = section::Options::GAME_PLAY_1P; section::options = section::Options::GAME_PLAY_1P;
#elif DEBUG #elif DEBUG
section::name = section::Name::LOGO; section::name = section::Name::GAME;
#else // NORMAL GAME #else // NORMAL GAME
section::name = section::Name::LOGO; section::name = section::Name::LOGO;
section::attract_mode = section::AttractMode::TITLE_TO_DEMO; section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
@@ -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;
@@ -380,6 +388,7 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/music/credits.ogg", AssetType::MUSIC); Asset::get()->add(prefix + "/data/music/credits.ogg", AssetType::MUSIC);
// Sonidos // Sonidos
Asset::get()->add(prefix + "/data/sound/game_start.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/balloon.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/balloon.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bubble1.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/bubble1.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bubble2.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/bubble2.wav", AssetType::SOUND);
@@ -397,6 +406,11 @@ 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);
Asset::get()->add(prefix + "/data/sound/voice_get_ready.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/tabe.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);
@@ -439,6 +453,11 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/gfx/bullet/bullet.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/bullet/bullet.png", AssetType::BITMAP);
} }
{ // Tabe
Asset::get()->add(prefix + "/data/gfx/tabe/tabe.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/tabe/tabe.ani", AssetType::ANIMATION);
}
{ // Juego { // Juego
Asset::get()->add(prefix + "/data/gfx/game/game_buildings.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/game/game_buildings.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_clouds1.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/game/game_clouds1.png", AssetType::BITMAP);

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
@@ -121,7 +123,6 @@ void Fade::update()
// Dibuja sobre el backbuffer_ // Dibuja sobre el backbuffer_
auto temp = SDL_GetRenderTarget(renderer_); auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_); SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE); SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_); SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
@@ -133,12 +134,12 @@ void Fade::update()
SDL_RenderFillRect(renderer_, &square_[index2]); SDL_RenderFillRect(renderer_, &square_[index2]);
} }
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND);
// Deja el renderizador como estaba // Deja el renderizador como estaba
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_)
{ {
@@ -156,9 +157,11 @@ void Fade::update()
// Dibuja sobre el backbuffer_ // Dibuja sobre el backbuffer_
auto temp = SDL_GetRenderTarget(renderer_); auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_); SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_); SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
for (auto rect : square_)
// Dibuja el cuadrado correspondiente
for (const auto rect : square_)
{ {
SDL_RenderFillRect(renderer_, &rect); SDL_RenderFillRect(renderer_, &rect);
} }
@@ -166,11 +169,12 @@ void Fade::update()
// Deja el renderizador como estaba // Deja el renderizador como estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
const auto h = counter_ / 3; // Modifica el tamaño de los rectangulos
for (int i = 0; i < (int)square_.size(); ++i) const auto h = counter_ / 2;
for (size_t i = 0; i < square_.size(); ++i)
{ {
// A partir del segundo rectangulo se pinta en función del anterior // A partir del segundo rectangulo se pinta en función del anterior
square_[i].h = i == 0 ? h : std::max(square_[i - 1].h - 3, 0); square_.at(i).h = i == 0 ? h : std::max(square_.at(i - 1).h - 2, 0);
} }
} }
else else
@@ -251,12 +255,8 @@ void Fade::activate()
} }
// Limpia la textura // Limpia la textura
auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_);
a_ = mode_ == FadeMode::OUT ? 0 : 255; a_ = mode_ == FadeMode::OUT ? 0 : 255;
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_); cleanBackbuffer(r_, g_, b_, a_);
SDL_RenderClear(renderer_);
SDL_SetRenderTarget(renderer_, temp);
// Deja el color listo para usar // Deja el color listo para usar
a_ = mode_ == FadeMode::OUT ? 255 : 0; a_ = mode_ == FadeMode::OUT ? 255 : 0;
@@ -266,12 +266,16 @@ void Fade::activate()
case FadeType::VENETIAN: case FadeType::VENETIAN:
{ {
cleanBackbuffer(0, 0, 0, 0); // Limpia la textura
rect1_ = {0, 0, param.game.width, 0}; a_ = mode_ == FadeMode::OUT ? 0 : 255;
square_.clear(); cleanBackbuffer(r_, g_, b_, a_);
a_ = 255;
// Deja el color listo para usar
a_ = mode_ == FadeMode::OUT ? 255 : 0;
// Añade los cuadrados al vector // Añade los cuadrados al vector
square_.clear();
rect1_ = {0, 0, param.game.width, 0};
const int max = param.game.height / param.fade.venetian_size; const int max = param.game.height / param.fade.venetian_size;
for (int i = 0; i < max; ++i) for (int i = 0; i < max; ++i)
@@ -285,31 +289,6 @@ void Fade::activate()
} }
} }
// Comprueba si está activo
bool Fade::isEnabled() const
{
return enabled_;
}
// Comprueba si ha terminado la transicion
bool Fade::hasEnded() const
{
// Ha terminado cuando ha finalizado la transición y se ha deshabilitado
return !enabled_ && finished_;
}
// Establece el tipo de fade
void Fade::setType(FadeType type)
{
type_ = type;
}
// Establece el modo de fade
void Fade::setMode(FadeMode mode)
{
mode_ = mode;
}
// Establece el color del fade // Establece el color del fade
void Fade::setColor(Uint8 r, Uint8 g, Uint8 b) void Fade::setColor(Uint8 r, Uint8 g, Uint8 b)
{ {
@@ -318,12 +297,6 @@ void Fade::setColor(Uint8 r, Uint8 g, Uint8 b)
b_ = b; b_ = b;
} }
// Establece la duración posterior
void Fade::setPost(int value)
{
post_duration_ = value;
}
// Limpia el backbuffer // Limpia el backbuffer
void Fade::cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a) void Fade::cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{ {
@@ -337,4 +310,14 @@ 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();
@@ -71,21 +75,16 @@ public:
// Activa el fade // Activa el fade
void activate(); void activate();
// Comprueba si ha terminado la transicion
bool hasEnded() const;
// Comprueba si está activo
bool isEnabled() const;
// Establece el tipo de fade
void setType(FadeType type);
// Establece el modo de fade
void setMode(FadeMode mode);
// Establece el color del fade // Establece el color del fade
void setColor(Uint8 r, Uint8 g, Uint8 b); void setColor(Uint8 r, Uint8 g, Uint8 b);
// Establece la duración posterior // Getters
void setPost(int value); int getValue() const { return value_; }
bool isEnabled() const { return enabled_; }
bool hasEnded() const { return !enabled_ && finished_; }
// Setters
void setType(FadeType type) { type_ = type; }
void setMode(FadeMode mode) { mode_ = mode; }
void setPost(int value) { post_duration_ = value; }
}; };

View File

@@ -32,6 +32,7 @@
#include "section.h" // Para Name, name, Options, options #include "section.h" // Para Name, name, Options, options
#include "smart_sprite.h" // Para SmartSprite #include "smart_sprite.h" // Para SmartSprite
#include "stage.h" // Para number, get, Stage, power, total_p... #include "stage.h" // Para number, get, Stage, power, total_p...
#include "tabe.h" // Para Tabe
#include "text.h" // Para Text #include "text.h" // Para Text
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
struct JA_Sound_t; // lines 37-37 struct JA_Sound_t; // lines 37-37
@@ -44,8 +45,10 @@ 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>()),
balloon_manager_(std::make_unique<BalloonManager>()) fade_out_(std::make_unique<Fade>()),
balloon_manager_(std::make_unique<BalloonManager>()),
tabe_(std::make_unique<Tabe>())
{ {
// Pasa variables // Pasa variables
demo_.enabled = demo; demo_.enabled = demo;
@@ -63,9 +66,17 @@ 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(0);
fade_->setType(FadeType::VENETIAN); fade_in_->setType(FadeType::VENETIAN);
fade_in_->setMode(FadeMode::IN);
fade_in_->activate();
// JA_PlaySound(Resource::get()->getSound("fade_in.wav"));
// playMusic();
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);
@@ -87,24 +98,25 @@ Game::Game(int player_id, int current_stage, bool demo)
Stage::total_power += Stage::get(i).power_to_complete; Stage::total_power += Stage::get(i).power_to_complete;
} }
#endif #endif
// Crea los primeros globos y el mensaje de inicio
if (!demo_.enabled)
{
balloon_manager_->createTwoBigBalloons();
evaluateAndSetMenace();
createMessage({paths_.at(0), paths_.at(1)}, Resource::get()->getTexture("get_ready"));
}
} }
Game::~Game() Game::~Game()
{ {
// Guarda las puntuaciones en un fichero // MODO DEMO
if (!demo_.enabled) if (demo_.enabled)
{ {
// Habilita los sonidos
JA_EnableSound(true);
}
// MODO JUEGO
else
{
// Guarda las puntuaciones en un fichero
auto manager = std::make_unique<ManageHiScoreTable>(options.game.hi_score_table); auto manager = std::make_unique<ManageHiScoreTable>(options.game.hi_score_table);
manager->saveToFile(asset_->get("score.bin")); manager->saveToFile(asset_->get("score.bin"));
section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
} }
#ifdef RECORDING #ifdef RECORDING
saveDemoFile(Asset::get()->get("demo1.bin"), demo_.data.at(0)); saveDemoFile(Asset::get()->get("demo1.bin"), demo_.data.at(0));
#endif #endif
@@ -213,8 +225,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();
} }
} }
@@ -262,7 +274,7 @@ void Game::updateStage()
std::vector<Path> paths = {paths_.at(2), paths_.at(3)}; std::vector<Path> paths = {paths_.at(2), paths_.at(3)};
if (Stage::number == 9) if (Stage::number == 9)
{ {
createMessage(paths, Resource::get()->getTexture("last_stage")); createMessage(paths, Resource::get()->getTexture("game_text_last_stage"));
} }
else else
{ {
@@ -275,6 +287,27 @@ void Game::updateStage()
} }
} }
// Actualiza el estado de fade in
void Game::updateFadeInState()
{
if (state_ == GameState::FADE_IN)
{
if (fade_in_->hasEnded())
{
state_ = GameState::PLAYING;
// Crea los primeros globos y el mensaje de inicio
if (!demo_.enabled)
{
balloon_manager_->createTwoBigBalloons();
evaluateAndSetMenace();
createMessage({paths_.at(0), paths_.at(1)}, Resource::get()->getTexture("game_text_get_ready"));
JA_PlaySound(Resource::get()->getSound("voice_get_ready.wav"));
}
}
}
}
// Actualiza el estado de fin de la partida // Actualiza el estado de fin de la partida
void Game::updateGameOverState() void Game::updateGameOverState()
{ {
@@ -283,25 +316,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_text_game_over"));
JA_FadeOutMusic(1000);
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)
{ {
@@ -336,8 +365,8 @@ void Game::updateCompletedState()
// Muestra el mensaje de felicitación y da los puntos a los jugadores // Muestra el mensaje de felicitación y da los puntos a los jugadores
if (game_completed_counter_ == 200) if (game_completed_counter_ == 200)
{ {
createMessage({paths_.at(4), paths_.at(5)}, Resource::get()->getTexture("congratulations")); createMessage({paths_.at(4), paths_.at(5)}, Resource::get()->getTexture("game_text_congratulations"));
createMessage({paths_.at(6), paths_.at(7)}, Resource::get()->getTexture("1000000_points")); createMessage({paths_.at(6), paths_.at(7)}, Resource::get()->getTexture("game_text_1000000_points"));
for (auto &player : players_) for (auto &player : players_)
if (player->isPlaying()) if (player->isPlaying())
@@ -474,6 +503,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 +514,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 +753,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 +848,12 @@ 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();
} }
} }
@@ -869,7 +901,7 @@ void Game::update()
checkMusicStatus(); checkMusicStatus();
screen_->update(); screen_->update();
globalInputs::update(); globalInputs::update();
fillCanvas(); fillCanvas();
} }
} }
@@ -911,12 +943,14 @@ void Game::fillCanvas()
background_->render(); background_->render();
renderItems(); renderItems();
renderSmartSprites(); renderSmartSprites();
tabe_->render();
balloon_manager_->render(); balloon_manager_->render();
renderBullets(); renderBullets();
renderPathSprites(); renderPathSprites();
renderPlayers(); renderPlayers();
// dbg_print(0, 40, std::to_string(menace_current_).c_str(), 255, 0, 0);
// dbg_print(0, 50, std::to_string(menace_threshold_).c_str(), 255, 0, 0); auto sprite = std::make_unique<Sprite>(Resource::get()->getTexture("game_text_game_over"));
sprite->render();
// Deja el renderizador apuntando donde estaba // Deja el renderizador apuntando donde estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
@@ -935,7 +969,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 +995,11 @@ 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) if (state_ != GameState::COMPLETED && !allPlayersAreGameOver())
// 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")); playMusic();
}
} }
// Bucle para el juego // Bucle para el juego
@@ -988,7 +1024,7 @@ void Game::initPaths()
{ {
// Recorrido para el texto de "Get Ready!" (0,1) // Recorrido para el texto de "Get Ready!" (0,1)
{ {
const auto &texture = Resource::get()->getTexture("get_ready"); const auto &texture = Resource::get()->getTexture("game_text_get_ready");
const auto w = texture->getWidth(); const auto w = texture->getWidth();
const int x0 = -w; const int x0 = -w;
const int x1 = param.game.play_area.center_x - w / 2; const int x1 = param.game.play_area.center_x - w / 2;
@@ -998,10 +1034,9 @@ 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("game_text_last_stage");
const auto h = texture->getHeight(); const auto h = texture->getHeight();
const int y0 = param.game.play_area.rect.h - h; const int y0 = param.game.play_area.rect.h - h;
const int y1 = param.game.play_area.center_y - h / 2; const int y1 = param.game.play_area.center_y - h / 2;
@@ -1013,7 +1048,7 @@ void Game::initPaths()
// Recorrido para el texto de "Congratulations!!" (3,4) // Recorrido para el texto de "Congratulations!!" (3,4)
{ {
const auto &texture = Resource::get()->getTexture("congratulations"); const auto &texture = Resource::get()->getTexture("game_text_congratulations");
const auto w = texture->getWidth(); const auto w = texture->getWidth();
const auto h = texture->getHeight(); const auto h = texture->getHeight();
const int x0 = -w; const int x0 = -w;
@@ -1026,7 +1061,7 @@ void Game::initPaths()
// Recorrido para el texto de "1.000.000 points!" (5,6) // Recorrido para el texto de "1.000.000 points!" (5,6)
{ {
const auto &texture = Resource::get()->getTexture("1000000_points"); const auto &texture = Resource::get()->getTexture("game_text_1000000_points");
const auto w = texture->getWidth(); const auto w = texture->getWidth();
const auto h = texture->getHeight(); const auto h = texture->getHeight();
const int x0 = param.game.play_area.rect.w; const int x0 = param.game.play_area.rect.w;
@@ -1164,8 +1199,7 @@ void Game::checkEvents()
} }
case SDLK_6: // Crea un mensaje case SDLK_6: // Crea un mensaje
{ {
createMessage({paths_.at(4), paths_.at(5)}, Resource::get()->getTexture("congratulations")); createMessage({paths_.at(2), paths_.at(3)}, Resource::get()->getTexture("game_text_congratulations"));
createMessage({paths_.at(6), paths_.at(7)}, Resource::get()->getTexture("1000000_points"));
break; break;
} }
case SDLK_7: // Flash case SDLK_7: // Flash
@@ -1176,6 +1210,12 @@ void Game::checkEvents()
case SDLK_8: case SDLK_8:
{ {
players_.at(0)->setPlayingState(PlayerState::LEAVING_SCREEN); players_.at(0)->setPlayingState(PlayerState::LEAVING_SCREEN);
break;
}
case SDLK_9:
{
tabe_->enable();
break;
} }
default: default:
break; break;
@@ -1342,7 +1382,8 @@ void Game::handleDemoMode()
if (input_->checkAnyButtonPressed()) if (input_->checkAnyButtonPressed())
{ {
section::name = section::Name::TITLE; // Salir del modo demo y regresar al menú principal. section::name = section::Name::TITLE; // Salir del modo demo y regresar al menú principal.
section::attract_mode = section::AttractMode::TITLE_TO_DEMO; // El juego volverá a mostrar la demo
return; return;
} }
++index; ++index;
@@ -1691,6 +1732,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 +1763,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,15 +1807,18 @@ 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();
updateBackground(); updateBackground();
balloon_manager_->update(); balloon_manager_->update();
tabe_->update();
moveBullets(); moveBullets();
updateItems(); updateItems();
updateStage(); updateStage();
updateFadeInState();
updateGameOverState(); updateGameOverState();
updateCompletedState(); updateCompletedState();
updateSmartSprites(); updateSmartSprites();
@@ -1792,21 +1846,24 @@ void Game::cleanVectors()
// Gestiona el nivel de amenaza // Gestiona el nivel de amenaza
void Game::updateMenace() void Game::updateMenace()
{ {
const auto stage = Stage::get(Stage::number); if (state_ == GameState::PLAYING)
const float percent = Stage::power / stage.power_to_complete;
const int difference = stage.max_menace - stage.min_menace;
// Aumenta el nivel de amenaza en función de la puntuación
menace_threshold_ = stage.min_menace + (difference * percent);
// Si el nivel de amenza es inferior al umbral
if (menace_current_ < menace_threshold_)
{ {
// Crea una formación de enemigos const auto stage = Stage::get(Stage::number);
balloon_manager_->deployBalloonFormation(Stage::number); const float percent = Stage::power / stage.power_to_complete;
const int difference = stage.max_menace - stage.min_menace;
// Recalcula el nivel de amenaza con el nuevo globo // Aumenta el nivel de amenaza en función de la puntuación
evaluateAndSetMenace(); menace_threshold_ = stage.min_menace + (difference * percent);
// Si el nivel de amenza es inferior al umbral
if (menace_current_ < menace_threshold_)
{
// Crea una formación de enemigos
balloon_manager_->deployBalloonFormation(Stage::number);
// Recalcula el nivel de amenaza con el nuevo globo
evaluateAndSetMenace();
}
} }
} }

View File

@@ -12,6 +12,7 @@
class Asset; // lines 13-13 class Asset; // lines 13-13
class Background; // lines 14-14 class Background; // lines 14-14
class BalloonManager; class BalloonManager;
class Tabe;
class Bullet; // lines 15-15 class Bullet; // lines 15-15
class Fade; // lines 16-16 class Fade; // lines 16-16
class Input; // lines 17-17 class Input; // lines 17-17
@@ -65,6 +66,7 @@ private:
// Enum // Enum
enum class GameState enum class GameState
{ {
FADE_IN,
PLAYING, PLAYING,
COMPLETED, COMPLETED,
GAME_OVER, GAME_OVER,
@@ -140,8 +142,10 @@ 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::unique_ptr<Tabe> tabe_; // Objeto para gestionar el Tabe Volaor
std::vector<Path> paths_; // Vector con los recorridos precalculados almacenados std::vector<Path> paths_; // Vector con los recorridos precalculados almacenados
// Variables // Variables
@@ -164,7 +168,7 @@ private:
int total_power_to_complete_game_; // La suma del poder necesario para completar todas las fases int total_power_to_complete_game_; // La suma del poder necesario para completar todas las fases
int menace_current_ = 0; // Nivel de amenaza actual int menace_current_ = 0; // Nivel de amenaza actual
int menace_threshold_ = 0; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos int menace_threshold_ = 0; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos
GameState state_ = GameState::PLAYING; // Estado GameState state_ = GameState::FADE_IN; // Estado
#ifdef DEBUG #ifdef DEBUG
bool auto_pop_balloons_ = false; // Si es true, incrementa automaticamente los globos explotados bool auto_pop_balloons_ = false; // Si es true, incrementa automaticamente los globos explotados
#endif #endif
@@ -193,6 +197,9 @@ private:
// Comprueba si hay cambio de fase y actualiza las variables // Comprueba si hay cambio de fase y actualiza las variables
void updateStage(); void updateStage();
// Actualiza el estado de fade in
void updateFadeInState();
// Actualiza el estado de fin de la partida // Actualiza el estado de fin de la partida
void updateGameOverState(); void updateGameOverState();
@@ -373,6 +380,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

@@ -205,9 +205,10 @@ void HiScoreTable::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(); //JA_StopMusic();
section::name = section::Name::TITLE; section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1; section::options = section::Options::TITLE_1;
section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
return; return;
} }

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

@@ -310,9 +310,10 @@ void Instructions::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(); //JA_StopMusic();
section::name = section::Name::TITLE; section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1; section::options = section::Options::TITLE_1;
section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
return; return;
} }

View File

@@ -1,91 +1,91 @@
#ifndef JA_USESDLMIXER #ifndef JA_USESDLMIXER
#include "jail_audio.h" #include "jail_audio.h"
#include <stdint.h> // para uint8_t #include "stb_vorbis.c"
#include <stdio.h> // para NULL, fseek, fclose, fopen, fread, ftell, FILE #include <SDL2/SDL.h>
#include <stdlib.h> // para free, malloc #include <stdio.h>
#include "stb_vorbis.c" // para stb_vorbis_decode_memory
#define JA_MAX_SIMULTANEOUS_CHANNELS 5 #define JA_MAX_SIMULTANEOUS_CHANNELS 20
struct JA_Sound_t struct JA_Sound_t {
{ Uint32 length {0};
Uint32 length{0}; Uint8* buffer {NULL};
Uint8 *buffer{NULL};
}; };
struct JA_Channel_t struct JA_Channel_t {
{ JA_Sound_t *sound;
JA_Sound_t *sound; int pos {0};
int pos{0}; int times {0};
int times{0}; JA_Channel_state state { JA_CHANNEL_FREE };
JA_Channel_state state{JA_CHANNEL_FREE};
}; };
struct JA_Music_t struct JA_Music_t {
{ int samples {0};
int samples{0}; int pos {0};
int pos{0}; int times {0};
int times{0}; short* output {NULL};
short *output{NULL}; JA_Music_state state {JA_MUSIC_INVALID};
JA_Music_state state{JA_MUSIC_INVALID};
}; };
JA_Music_t *current_music{NULL}; JA_Music_t *current_music{NULL};
JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS]; JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS];
int JA_freq{48000}; int JA_freq {48000};
SDL_AudioFormat JA_format{AUDIO_S16}; SDL_AudioFormat JA_format {AUDIO_S16};
Uint8 JA_channels{2}; Uint8 JA_channels {2};
int JA_musicVolume = 128; int JA_musicVolume = 128;
int JA_soundVolume = 64; int JA_soundVolume = 64;
bool JA_musicEnabled = true; bool JA_musicEnabled = true;
bool JA_soundEnabled = true; bool JA_soundEnabled = true;
SDL_AudioDeviceID sdlAudioDevice = 0; SDL_AudioDeviceID sdlAudioDevice = 0;
void audioCallback(void *userdata, uint8_t *stream, int len) bool fading = false;
{ int fade_start_time;
int fade_duration;
int fade_initial_volume;
void audioCallback(void * userdata, uint8_t * stream, int len) {
SDL_memset(stream, 0, len); SDL_memset(stream, 0, len);
if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING) if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING) {
{ int volume = JA_musicVolume;
const int size = SDL_min(len, current_music->samples * 2 - current_music->pos); if (fading) {
SDL_MixAudioFormat(stream, (Uint8 *)(current_music->output + current_music->pos), AUDIO_S16, size, JA_musicVolume); int time = SDL_GetTicks();
current_music->pos += size / 2; if (time > (fade_start_time+fade_duration)) {
if (size < len) fading = false;
{ current_music->pos = 0;
if (current_music->times != 0) current_music->state = JA_MUSIC_STOPPED;
{ volume = 0;
SDL_MixAudioFormat(stream + size, (Uint8 *)current_music->output, AUDIO_S16, len - size, JA_musicVolume); } else {
current_music->pos = (len - size) / 2; const int time_passed = time - fade_start_time;
if (current_music->times > 0) const float percent = (float)time_passed / (float)fade_duration;
current_music->times--; volume = JA_musicVolume * (1.0 - percent);
} }
else }
{ const int size = SDL_min(len, (current_music->samples-current_music->pos)*2);
SDL_MixAudioFormat(stream, (Uint8*)(current_music->output+current_music->pos), AUDIO_S16, size, volume);
current_music->pos += size/2;
if (size < len) {
if (current_music->times != 0) {
SDL_MixAudioFormat(stream+size, (Uint8*)current_music->output, AUDIO_S16, len-size, volume);
current_music->pos = (len-size)/2;
if (current_music->times > 0) current_music->times--;
} else {
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
} }
} }
} }
// Mixar els channels mi amol // Mixar els channels mi amol
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
{ if (channels[i].state == JA_CHANNEL_PLAYING) {
if (channels[i].state == JA_CHANNEL_PLAYING)
{
const int size = SDL_min(len, channels[i].sound->length - channels[i].pos); const int size = SDL_min(len, channels[i].sound->length - channels[i].pos);
SDL_MixAudioFormat(stream, channels[i].sound->buffer + channels[i].pos, AUDIO_S16, size, JA_soundVolume); SDL_MixAudioFormat(stream, channels[i].sound->buffer + channels[i].pos, AUDIO_S16, size, JA_soundVolume);
channels[i].pos += size; channels[i].pos += size;
if (size < len) if (size < len) {
{ if (channels[i].times != 0) {
if (channels[i].times != 0) SDL_MixAudioFormat(stream + size, channels[i].sound->buffer, AUDIO_S16, len-size, JA_soundVolume);
{ channels[i].pos = len-size;
SDL_MixAudioFormat(stream + size, channels[i].sound->buffer, AUDIO_S16, len - size, JA_soundVolume); if (channels[i].times > 0) channels[i].times--;
channels[i].pos = len - size; } else {
if (channels[i].times > 0)
channels[i].times--;
}
else
{
JA_StopChannel(i); JA_StopChannel(i);
} }
} }
@@ -95,55 +95,52 @@ void audioCallback(void *userdata, uint8_t *stream, int len)
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels) void JA_Init(const int freq, const SDL_AudioFormat format, const int channels)
{ {
#ifdef DEBUG
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
#endif
SDL_Log("Iniciant JailAudio...");
JA_freq = freq; JA_freq = freq;
JA_format = format; JA_format = format;
JA_channels = channels; JA_channels = channels;
SDL_AudioSpec audioSpec{JA_freq, JA_format, JA_channels, 0, 1024, 0, 0, audioCallback, NULL}; SDL_AudioSpec audioSpec{JA_freq, JA_format, JA_channels, 0, 1024, 0, 0, audioCallback, NULL};
if (sdlAudioDevice != 0) if (sdlAudioDevice != 0) SDL_CloseAudioDevice(sdlAudioDevice);
SDL_CloseAudioDevice(sdlAudioDevice);
sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0); sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0);
if (sdlAudioDevice==0)
{
SDL_Log("FAILED!\n");
SDL_Log("Failed to initialize SDL audio!\n");
} else {
SDL_Log("OK!\n");
}
SDL_PauseAudioDevice(sdlAudioDevice, 0); SDL_PauseAudioDevice(sdlAudioDevice, 0);
} }
void JA_Quit() void JA_Quit() {
{
SDL_PauseAudioDevice(sdlAudioDevice, 1); SDL_PauseAudioDevice(sdlAudioDevice, 1);
if (sdlAudioDevice != 0) if (sdlAudioDevice != 0) SDL_CloseAudioDevice(sdlAudioDevice);
SDL_CloseAudioDevice(sdlAudioDevice);
sdlAudioDevice = 0; sdlAudioDevice = 0;
} }
JA_Music_t *JA_LoadMusic(const char *filename) JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length)
{ {
int chan, samplerate; int chan, samplerate;
// [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid.
FILE *f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
Uint8 *buffer = (Uint8 *)malloc(fsize + 1);
if (fread(buffer, fsize, 1, f) != 1)
return NULL;
fclose(f);
JA_Music_t *music = new JA_Music_t(); JA_Music_t *music = new JA_Music_t();
music->samples = stb_vorbis_decode_memory(buffer, fsize, &chan, &samplerate, &music->output); music->samples = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &music->output);
free(buffer);
// [RZC 28/08/22] Abans el descomprimiem mentre el teniem obert // [RZC 28/08/22] Abans el descomprimiem mentre el teniem obert
// music->samples = stb_vorbis_decode_filename(filename, &chan, &samplerate, &music->output); // music->samples = stb_vorbis_decode_filename(filename, &chan, &samplerate, &music->output);
SDL_AudioCVT cvt; SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, AUDIO_S16, chan, samplerate, JA_format, JA_channels, JA_freq); SDL_BuildAudioCVT(&cvt, AUDIO_S16, chan, samplerate, JA_format, JA_channels, JA_freq);
if (cvt.needed) SDL_Log("Music length: %f\n", float(music->samples)/float(JA_freq));
{ if (cvt.needed) {
cvt.len = music->samples * chan * 2; cvt.len = music->samples * chan * 2;
cvt.buf = (Uint8 *)SDL_malloc(cvt.len * cvt.len_mult); cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult);
SDL_memcpy(cvt.buf, music->output, cvt.len); SDL_memcpy(cvt.buf, music->output, cvt.len);
SDL_ConvertAudio(&cvt); SDL_ConvertAudio(&cvt);
free(music->output); free(music->output);
music->output = (short *)cvt.buf; music->output = (short*)cvt.buf;
} }
music->pos = 0; music->pos = 0;
music->state = JA_MUSIC_STOPPED; music->state = JA_MUSIC_STOPPED;
@@ -151,13 +148,29 @@ JA_Music_t *JA_LoadMusic(const char *filename)
return music; return music;
} }
JA_Music_t *JA_LoadMusic(const char* filename)
{
// [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid.
FILE *f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
Uint8 *buffer = (Uint8*)malloc(fsize + 1);
if (fread(buffer, fsize, 1, f)!=1) return NULL;
fclose(f);
JA_Music_t *music = JA_LoadMusic(buffer, fsize);
free(buffer);
return music;
}
void JA_PlayMusic(JA_Music_t *music, const int loop) void JA_PlayMusic(JA_Music_t *music, const int loop)
{ {
if (!JA_musicEnabled || !music) if (!JA_musicEnabled) return;
return;
if (current_music != NULL) if (current_music != NULL) {
{
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
} }
@@ -169,78 +182,108 @@ void JA_PlayMusic(JA_Music_t *music, const int loop)
void JA_PauseMusic() void JA_PauseMusic()
{ {
if (!JA_musicEnabled) if (!JA_musicEnabled) return;
return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
return;
current_music->state = JA_MUSIC_PAUSED; current_music->state = JA_MUSIC_PAUSED;
} }
void JA_ResumeMusic() void JA_ResumeMusic()
{ {
if (!JA_musicEnabled) if (!JA_musicEnabled) return;
return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
return;
current_music->state = JA_MUSIC_PLAYING; current_music->state = JA_MUSIC_PLAYING;
} }
void JA_StopMusic() void JA_StopMusic()
{ {
if (!JA_musicEnabled) if (!JA_musicEnabled) return;
return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
return;
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
} }
JA_Music_state JA_GetMusicState() void JA_FadeOutMusic(const int milliseconds)
{ {
if (!JA_musicEnabled) if (!JA_musicEnabled) return;
return JA_MUSIC_DISABLED; if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
if (current_music == NULL) fading = true;
return JA_MUSIC_INVALID; fade_start_time = SDL_GetTicks();
fade_duration = milliseconds;
fade_initial_volume = JA_musicVolume;
}
JA_Music_state JA_GetMusicState() {
if (!JA_musicEnabled) return JA_MUSIC_DISABLED;
if (current_music == NULL) return JA_MUSIC_INVALID;
return current_music->state; return current_music->state;
} }
void JA_DeleteMusic(JA_Music_t *music) void JA_DeleteMusic(JA_Music_t *music) {
{ if (current_music == music) current_music = NULL;
if (current_music == music)
current_music = NULL;
free(music->output); free(music->output);
delete music; delete music;
} }
int JA_SetMusicVolume(int volume) int JA_SetMusicVolume(int volume)
{ {
JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume;
: volume;
return JA_musicVolume; return JA_musicVolume;
} }
void JA_SetMusicPosition(float value)
{
if (!current_music) return;
current_music->pos = value * JA_freq;
}
float JA_GetMusicPosition()
{
if (!current_music) return 0;
return float(current_music->pos)/float(JA_freq);
}
void JA_EnableMusic(const bool value) void JA_EnableMusic(const bool value)
{ {
if (!value && current_music != NULL && current_music->state == JA_MUSIC_PLAYING) if (!value && current_music != NULL && current_music->state==JA_MUSIC_PLAYING) JA_StopMusic();
JA_StopMusic();
JA_musicEnabled = value; JA_musicEnabled = value;
} }
JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length)
{
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length) {
JA_Sound_t *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
sound->buffer = buffer; sound->buffer = buffer;
sound->length = length; sound->length = length;
return sound; return sound;
} }
JA_Sound_t *JA_LoadSound(const char *filename) JA_Sound_t *JA_LoadSound(uint8_t* buffer, uint32_t size) {
{ JA_Sound_t *sound = new JA_Sound_t();
SDL_AudioSpec wavSpec;
SDL_LoadWAV_RW(SDL_RWFromMem(buffer, size),1, &wavSpec, &sound->buffer, &sound->length);
SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, wavSpec.format, wavSpec.channels, wavSpec.freq, JA_format, JA_channels, JA_freq);
cvt.len = sound->length;
cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult);
SDL_memcpy(cvt.buf, sound->buffer, sound->length);
SDL_ConvertAudio(&cvt);
SDL_FreeWAV(sound->buffer);
sound->buffer = cvt.buf;
sound->length = cvt.len_cvt;
return sound;
}
JA_Sound_t *JA_LoadSound(const char* filename) {
JA_Sound_t *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
SDL_AudioSpec wavSpec; SDL_AudioSpec wavSpec;
SDL_LoadWAV(filename, &wavSpec, &sound->buffer, &sound->length); SDL_LoadWAV(filename, &wavSpec, &sound->buffer, &sound->length);
@@ -248,7 +291,7 @@ JA_Sound_t *JA_LoadSound(const char *filename)
SDL_AudioCVT cvt; SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, wavSpec.format, wavSpec.channels, wavSpec.freq, JA_format, JA_channels, JA_freq); SDL_BuildAudioCVT(&cvt, wavSpec.format, wavSpec.channels, wavSpec.freq, JA_format, JA_channels, JA_freq);
cvt.len = sound->length; cvt.len = sound->length;
cvt.buf = (Uint8 *)SDL_malloc(cvt.len * cvt.len_mult); cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult);
SDL_memcpy(cvt.buf, sound->buffer, sound->length); SDL_memcpy(cvt.buf, sound->buffer, sound->length);
SDL_ConvertAudio(&cvt); SDL_ConvertAudio(&cvt);
SDL_FreeWAV(sound->buffer); SDL_FreeWAV(sound->buffer);
@@ -260,16 +303,11 @@ JA_Sound_t *JA_LoadSound(const char *filename)
int JA_PlaySound(JA_Sound_t *sound, const int loop) int JA_PlaySound(JA_Sound_t *sound, const int loop)
{ {
if (!JA_soundEnabled || !sound) if (!JA_soundEnabled) return -1;
return 0;
int channel = 0; int channel = 0;
while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; }
{ if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) channel = 0;
channel++;
}
if (channel == JA_MAX_SIMULTANEOUS_CHANNELS)
channel = 0;
channels[channel].sound = sound; channels[channel].sound = sound;
channels[channel].times = loop; channels[channel].times = loop;
@@ -280,10 +318,8 @@ int JA_PlaySound(JA_Sound_t *sound, const int loop)
void JA_DeleteSound(JA_Sound_t *sound) void JA_DeleteSound(JA_Sound_t *sound)
{ {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
{ if (channels[i].sound == sound) JA_StopChannel(i);
if (channels[i].sound == sound)
JA_StopChannel(i);
} }
SDL_free(sound->buffer); SDL_free(sound->buffer);
delete sound; delete sound;
@@ -291,60 +327,41 @@ void JA_DeleteSound(JA_Sound_t *sound)
void JA_PauseChannel(const int channel) void JA_PauseChannel(const int channel)
{ {
if (!JA_soundEnabled) if (!JA_soundEnabled) return;
return;
if (channel == -1) if (channel == -1) {
{ for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) if (channels[i].state == JA_CHANNEL_PLAYING) channels[i].state = JA_CHANNEL_PAUSED;
{
if (channels[i].state == JA_CHANNEL_PLAYING)
channels[i].state = JA_CHANNEL_PAUSED;
} }
} } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) if (channels[channel].state == JA_CHANNEL_PLAYING) channels[channel].state = JA_CHANNEL_PAUSED;
{
if (channels[channel].state == JA_CHANNEL_PLAYING)
channels[channel].state = JA_CHANNEL_PAUSED;
} }
} }
void JA_ResumeChannel(const int channel) void JA_ResumeChannel(const int channel)
{ {
if (!JA_soundEnabled) if (!JA_soundEnabled) return;
return;
if (channel == -1) if (channel == -1) {
{ for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) if (channels[i].state == JA_CHANNEL_PAUSED) channels[i].state = JA_CHANNEL_PLAYING;
{
if (channels[i].state == JA_CHANNEL_PAUSED)
channels[i].state = JA_CHANNEL_PLAYING;
} }
} } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) if (channels[channel].state == JA_CHANNEL_PAUSED) channels[channel].state = JA_CHANNEL_PLAYING;
{
if (channels[channel].state == JA_CHANNEL_PAUSED)
channels[channel].state = JA_CHANNEL_PLAYING;
} }
} }
void JA_StopChannel(const int channel) void JA_StopChannel(const int channel)
{ {
if (!JA_soundEnabled) if (!JA_soundEnabled) return;
return;
if (channel == -1) if (channel == -1) {
{ for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{
channels[i].state = JA_CHANNEL_FREE; channels[i].state = JA_CHANNEL_FREE;
channels[i].pos = 0; channels[i].pos = 0;
channels[i].sound = NULL; channels[i].sound = NULL;
} }
} } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
{
channels[channel].state = JA_CHANNEL_FREE; channels[channel].state = JA_CHANNEL_FREE;
channels[channel].pos = 0; channels[channel].pos = 0;
channels[channel].sound = NULL; channels[channel].sound = NULL;
@@ -353,18 +370,15 @@ void JA_StopChannel(const int channel)
JA_Channel_state JA_GetChannelState(const int channel) JA_Channel_state JA_GetChannelState(const int channel)
{ {
if (!JA_soundEnabled) if (!JA_soundEnabled) return JA_SOUND_DISABLED;
return JA_SOUND_DISABLED;
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID;
return JA_CHANNEL_INVALID;
return channels[channel].state; return channels[channel].state;
} }
int JA_SetSoundVolume(int volume) int JA_SetSoundVolume(int volume)
{ {
JA_soundVolume = volume > 128 ? 128 : volume < 0 ? 0 JA_soundVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume;
: volume;
return JA_soundVolume; return JA_soundVolume;
} }
@@ -372,17 +386,15 @@ void JA_EnableSound(const bool value)
{ {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{ {
if (channels[i].state == JA_CHANNEL_PLAYING) if (channels[i].state == JA_CHANNEL_PLAYING) JA_StopChannel(i);
JA_StopChannel(i);
} }
JA_soundEnabled = value; JA_soundEnabled = value;
} }
int JA_SetVolume(int volume) int JA_SetVolume(int volume)
{ {
JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume;
: volume; JA_soundVolume = JA_musicVolume/2;
JA_soundVolume = JA_musicVolume / 2;
return JA_musicVolume; return JA_musicVolume;
} }

View File

@@ -1,42 +1,32 @@
#pragma once #pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h> // para SDL_AudioFormat enum JA_Channel_state { JA_CHANNEL_INVALID, JA_CHANNEL_FREE, JA_CHANNEL_PLAYING, JA_CHANNEL_PAUSED, JA_SOUND_DISABLED };
#include <SDL2/SDL_stdinc.h> // para Uint32, Uint8 enum JA_Music_state { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED, JA_MUSIC_DISABLED };
struct JA_Music_t; // lines 5-5
struct JA_Sound_t; // lines 6-6
enum JA_Channel_state struct JA_Sound_t;
{ struct JA_Music_t;
JA_CHANNEL_INVALID,
JA_CHANNEL_FREE,
JA_CHANNEL_PLAYING,
JA_CHANNEL_PAUSED,
JA_SOUND_DISABLED
};
enum JA_Music_state
{
JA_MUSIC_INVALID,
JA_MUSIC_PLAYING,
JA_MUSIC_PAUSED,
JA_MUSIC_STOPPED,
JA_MUSIC_DISABLED
};
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels); void JA_Init(const int freq, const SDL_AudioFormat format, const int channels);
void JA_Quit(); void JA_Quit();
JA_Music_t *JA_LoadMusic(const char *filename); JA_Music_t *JA_LoadMusic(const char* filename);
JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length);
void JA_PlayMusic(JA_Music_t *music, const int loop = -1); void JA_PlayMusic(JA_Music_t *music, const int loop = -1);
void JA_PauseMusic(); void JA_PauseMusic();
void JA_ResumeMusic(); void JA_ResumeMusic();
void JA_StopMusic(); void JA_StopMusic();
void JA_FadeOutMusic(const int milliseconds);
JA_Music_state JA_GetMusicState(); JA_Music_state JA_GetMusicState();
void JA_DeleteMusic(JA_Music_t *music); void JA_DeleteMusic(JA_Music_t *music);
int JA_SetMusicVolume(int volume); int JA_SetMusicVolume(int volume);
void JA_SetMusicPosition(float value);
float JA_GetMusicPosition();
void JA_EnableMusic(const bool value); void JA_EnableMusic(const bool value);
JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length); JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length);
JA_Sound_t *JA_LoadSound(const char *filename); JA_Sound_t *JA_LoadSound(Uint8* buffer, Uint32 length);
JA_Sound_t *JA_LoadSound(const char* filename);
int JA_PlaySound(JA_Sound_t *sound, const int loop = 0); int JA_PlaySound(JA_Sound_t *sound, const int loop = 0);
void JA_PauseChannel(const int channel); void JA_PauseChannel(const int channel);
void JA_ResumeChannel(const int channel); void JA_ResumeChannel(const int channel);

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;
@@ -235,7 +234,7 @@ void Logo::render()
void Logo::run() void Logo::run()
{ {
// Detiene la música // Detiene la música
JA_StopMusic(); JA_FadeOutMusic(500);
while (section::name == section::Name::LOGO) while (section::name == section::Name::LOGO)
{ {

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

@@ -290,7 +290,7 @@ void Resource::createTextures()
NameAndText("game_text_powerup", lang::getText(117)), NameAndText("game_text_powerup", lang::getText(117)),
NameAndText("game_text_one_hit", lang::getText(118)), NameAndText("game_text_one_hit", lang::getText(118)),
NameAndText("game_text_stop", lang::getText(119)), NameAndText("game_text_stop", lang::getText(119)),
NameAndText("1000000_points", lang::getText(76))}; NameAndText("game_text_1000000_points", lang::getText(76))};
auto text = getText("04b_25"); auto text = getText("04b_25");
for (const auto &s : strings) for (const auto &s : strings)
@@ -301,10 +301,10 @@ void Resource::createTextures()
// Tamaño doble // Tamaño doble
std::vector<NameAndText> strings2X = { std::vector<NameAndText> strings2X = {
NameAndText("get_ready", lang::getText(75)), NameAndText("game_text_get_ready", lang::getText(75)),
NameAndText("last_stage", lang::getText(79)), NameAndText("game_text_last_stage", lang::getText(79)),
NameAndText("congratulations", lang::getText(50)), NameAndText("game_text_congratulations", lang::getText(50)),
NameAndText("game_over", "Game Over")}; NameAndText("game_text_game_over", "Game Over")};
auto text2 = getText("04b_25_2x"); auto text2 = getText("04b_25_2x");
for (const auto &s : strings2X) for (const auto &s : strings2X)

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();

145
source/tabe.cpp Normal file
View File

@@ -0,0 +1,145 @@
#include "tabe.h"
#include "resource.h"
#include "param.h"
#include "jail_audio.h"
#include <algorithm>
// Constructor
Tabe::Tabe()
: sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("tabe.png"), Resource::get()->getAnimation("tabe.ani"))) {}
// Actualiza la lógica
void Tabe::update()
{
if (enabled_)
{
sprite_->update();
move();
}
}
// Dibuja el objeto
void Tabe::render()
{
if (enabled_)
{
sprite_->render();
}
}
// Mueve el objeto
void Tabe::move()
{
const int x = static_cast<int>(x_);
speed_ += accel_;
x_ += speed_;
fly_distance_ -= std::abs(x - static_cast<int>(x_));
// Comprueba si sale por los bordes
const float min_x = param.game.game_area.rect.x - WIDTH_;
const float max_x = param.game.game_area.rect.x + param.game.game_area.rect.w;
switch (destiny_)
{
case TabeDirection::TO_THE_LEFT:
{
if (x_ < min_x)
{
enabled_ = false;
}
if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_ && direction_ == TabeDirection::TO_THE_RIGHT)
{
setRandomFlyPath(TabeDirection::TO_THE_LEFT, 80);
x_ = param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_;
}
break;
}
case TabeDirection::TO_THE_RIGHT:
{
if (x_ > max_x)
{
enabled_ = false;
}
if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT)
{
setRandomFlyPath(TabeDirection::TO_THE_RIGHT, 80);
x_ = param.game.game_area.rect.x;
}
break;
}
default:
break;
}
if (fly_distance_ <= 0)
{
if (waiting_counter_ > 0)
{
accel_ = speed_ = 0.0f;
--waiting_counter_;
}
else
{
constexpr int CHOICES = 4;
const TabeDirection left[CHOICES] = {TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_RIGHT};
const TabeDirection right[CHOICES] = {TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_RIGHT, TabeDirection::TO_THE_RIGHT, TabeDirection::TO_THE_RIGHT};
const TabeDirection direction = destiny_ == TabeDirection::TO_THE_LEFT ? left[rand() % CHOICES] : right[rand() % CHOICES];
setRandomFlyPath(direction, 20 + rand() % 40);
}
}
shiftSprite();
}
// Habilita el objeto
void Tabe::enable()
{
if (!enabled_)
{
enabled_ = true;
y_ = 20.0f;
// Establece una dirección aleatoria
destiny_ = direction_ = rand() % 2 == 0 ? TabeDirection::TO_THE_LEFT : TabeDirection::TO_THE_RIGHT;
// Establece la posición inicial
x_ = (direction_ == TabeDirection::TO_THE_LEFT) ? param.game.game_area.rect.x + param.game.game_area.rect.w : param.game.game_area.rect.x - WIDTH_;
// Crea una ruta de vuelo
setRandomFlyPath(direction_, 60);
shiftSprite();
}
}
// Establece un vuelo aleatorio
void Tabe::setRandomFlyPath(TabeDirection direction, int lenght)
{
direction_ = direction;
fly_distance_ = lenght;
waiting_counter_ = 5 + rand() % 15;
JA_PlaySound(Resource::get()->getSound("tabe.wav"));
constexpr float SPEED = 2.0f;
switch (direction)
{
case TabeDirection::TO_THE_LEFT:
{
speed_ = -1.0f * SPEED;
accel_ = -1.0f * (1 + rand() % 10) / 30.0f;
sprite_->setFlip(SDL_FLIP_NONE);
break;
}
case TabeDirection::TO_THE_RIGHT:
{
speed_ = SPEED;
accel_ = (1 + rand() % 10) / 30.0f;
sprite_->setFlip(SDL_FLIP_HORIZONTAL);
break;
}
default:
break;
}
}

58
source/tabe.h Normal file
View File

@@ -0,0 +1,58 @@
#pragma once
#include "animated_sprite.h"
#include <memory>
enum class TabeDirection : int
{
TO_THE_LEFT = 0,
TO_THE_RIGHT = 1,
};
// Clase Tabe
class Tabe
{
private:
// Constantes
static constexpr int WIDTH_ = 32;
static constexpr int HEIGHT_ = 32;
// Punteros
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los graficos y animaciones
// Variables
float x_ = 0; // Posición del objeto
float y_ = 0; // Posición del objeto
float speed_ = 0.0f; // Velocidad de movimiento del objeto
float accel_ = 0.0f; // Aceleración del objeto
int fly_distance_ = 0; // Distancia de vuelo
int waiting_counter_ = 0; // Tiempo que pasa quieto el objeto
bool enabled_ = false; // Indica si el objeto está activo
TabeDirection direction_; // Dirección del objeto
TabeDirection destiny_; // Destino del objeto
// Mueve el objeto
void move();
// Actualiza la posición del sprite
void shiftSprite() { sprite_->setPos(x_, y_); }
// Establece un vuelo aleatorio
void setRandomFlyPath(TabeDirection direction, int lenght);
public:
// Constructor
Tabe();
// Destructor
~Tabe() = default;
// Actualiza la lógica
void update();
// Dibuja el objeto
void render();
// Habilita el objeto
void enable();
};

View File

@@ -31,7 +31,7 @@ Title::Title()
fade_(std::make_unique<Fade>()), fade_(std::make_unique<Fade>()),
tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::RANDOM)), tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::RANDOM)),
game_logo_(std::make_unique<GameLogo>(param.game.game_area.center_x, param.title.title_c_c_position)), game_logo_(std::make_unique<GameLogo>(param.game.game_area.center_x, param.title.title_c_c_position)),
mini_logo_sprite_(std::make_unique<Sprite>(Resource::get()->getTexture("logo_jailgames_mini.png"))), mini_logo_sprite_(std::make_unique<Sprite>(Resource::get()->getTexture("logo_jailgames_mini.png"))),
define_buttons_(std::make_unique<DefineButtons>()), define_buttons_(std::make_unique<DefineButtons>()),
num_controllers_(Input::get()->getNumControllers()) num_controllers_(Input::get()->getNumControllers())
{ {
@@ -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
@@ -70,10 +71,11 @@ void Title::update()
Screen::get()->update(); Screen::get()->update();
// Actualiza las variables de globalInputs // Actualiza las variables de globalInputs
globalInputs::update(); globalInputs::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)
@@ -107,7 +109,10 @@ void Title::update()
// Reproduce la música // Reproduce la música
if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED)) if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED))
{ {
JA_PlayMusic(Resource::get()->getMusic("title.ogg")); if (!fade_->isEnabled())
{
JA_PlayMusic(Resource::get()->getMusic("title.ogg"));
}
} }
// Actualiza el logo con el título del juego // Actualiza el logo con el título del juego
@@ -252,9 +257,14 @@ void Title::checkInput()
{ {
if (section::options == section::Options::TITLE_2 || ALLOW_TITLE_ANIMATION_SKIP) if (section::options == section::Options::TITLE_2 || ALLOW_TITLE_ANIMATION_SKIP)
{ {
fade_->activate(); if (!fade_->isEnabled())
post_fade_ = controller.player_id; {
return; JA_PlaySound(Resource::get()->getSound("game_start.wav"));
JA_FadeOutMusic(1500);
fade_->activate();
post_fade_ = controller.player_id;
return;
}
} }
} }

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