This commit is contained in:
2025-11-19 20:21:45 +01:00
parent cbe71b5af4
commit 35ef99cf7c
25 changed files with 397 additions and 462 deletions

View File

@@ -2,81 +2,84 @@
// --- Includes --- // --- Includes ---
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <stdint.h> // Para uint32_t, uint8_t #include <stdint.h> // Para uint32_t, uint8_t
#include <stdio.h> // Para NULL, fseek, printf, fclose, fopen, fread, ftell, FILE, SEEK_END, SEEK_SET #include <stdio.h> // Para NULL, fseek, printf, fclose, fopen, fread, ftell, FILE, SEEK_END, SEEK_SET
#include <stdlib.h> // Para free, malloc #include <stdlib.h> // Para free, malloc
#include <string.h> // Para strcpy, strlen #include <string.h> // Para strcpy, strlen
#define STB_VORBIS_HEADER_ONLY #define STB_VORBIS_HEADER_ONLY
#include "external/stb_vorbis.h" // Para stb_vorbis_decode_memory #include "external/stb_vorbis.h" // Para stb_vorbis_decode_memory
// --- Public Enums --- // --- Public Enums ---
enum JA_Channel_state { JA_CHANNEL_INVALID, JA_CHANNEL_FREE, JA_CHANNEL_PLAYING, JA_CHANNEL_PAUSED, JA_SOUND_DISABLED }; enum JA_Channel_state { JA_CHANNEL_INVALID,
enum JA_Music_state { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED, JA_MUSIC_DISABLED }; 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 };
// --- Struct Definitions --- // --- Struct Definitions ---
#define JA_MAX_SIMULTANEOUS_CHANNELS 20 #define JA_MAX_SIMULTANEOUS_CHANNELS 20
#define JA_MAX_GROUPS 2 #define JA_MAX_GROUPS 2
struct JA_Sound_t struct JA_Sound_t {
{ SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000};
SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 }; Uint32 length{0};
Uint32 length { 0 }; Uint8* buffer{NULL};
Uint8 *buffer { NULL };
}; };
struct JA_Channel_t struct JA_Channel_t {
{ JA_Sound_t* sound{nullptr};
JA_Sound_t *sound { nullptr }; int pos{0};
int pos { 0 }; int times{0};
int times { 0 }; int group{0};
int group { 0 }; SDL_AudioStream* stream{nullptr};
SDL_AudioStream *stream { nullptr }; JA_Channel_state state{JA_CHANNEL_FREE};
JA_Channel_state state { JA_CHANNEL_FREE };
}; };
struct JA_Music_t struct JA_Music_t {
{ SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000};
SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 }; Uint32 length{0};
Uint32 length { 0 }; Uint8* buffer{nullptr};
Uint8 *buffer { nullptr }; char* filename{nullptr};
char *filename { nullptr };
int pos { 0 }; int pos{0};
int times { 0 }; int times{0};
SDL_AudioStream *stream { nullptr }; SDL_AudioStream* stream{nullptr};
JA_Music_state state { JA_MUSIC_INVALID }; JA_Music_state state{JA_MUSIC_INVALID};
}; };
// --- Internal Global State --- // --- Internal Global State ---
// Marcado 'inline' (C++17) para asegurar una única instancia. // Marcado 'inline' (C++17) para asegurar una única instancia.
inline JA_Music_t* current_music { nullptr }; inline JA_Music_t* current_music{nullptr};
inline JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS]; inline JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS];
inline SDL_AudioSpec JA_audioSpec { SDL_AUDIO_S16, 2, 48000 }; inline SDL_AudioSpec JA_audioSpec{SDL_AUDIO_S16, 2, 48000};
inline float JA_musicVolume { 1.0f }; inline float JA_musicVolume{1.0f};
inline float JA_soundVolume[JA_MAX_GROUPS]; inline float JA_soundVolume[JA_MAX_GROUPS];
inline bool JA_musicEnabled { true }; inline bool JA_musicEnabled{true};
inline bool JA_soundEnabled { true }; inline bool JA_soundEnabled{true};
inline SDL_AudioDeviceID sdlAudioDevice { 0 }; inline SDL_AudioDeviceID sdlAudioDevice{0};
inline bool fading { false }; inline bool fading{false};
inline int fade_start_time { 0 }; inline int fade_start_time{0};
inline int fade_duration { 0 }; inline int fade_duration{0};
inline float fade_initial_volume { 0.0f }; // Corregido de 'int' a 'float' inline float fade_initial_volume{0.0f}; // Corregido de 'int' a 'float'
// --- Forward Declarations --- // --- Forward Declarations ---
inline void JA_StopMusic(); inline void JA_StopMusic();
inline void JA_StopChannel(const int channel); inline void JA_StopChannel(const int channel);
inline int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop = 0, const int group = 0); inline int JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop = 0, const int group = 0);
// --- Core Functions --- // --- Core Functions ---
inline void JA_Update() inline void JA_Update() {
{ if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING) {
if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING)
{
if (fading) { if (fading) {
int time = SDL_GetTicks(); int time = SDL_GetTicks();
if (time > (fade_start_time + fade_duration)) { if (time > (fade_start_time + fade_duration)) {
@@ -90,67 +93,56 @@ inline void JA_Update()
} }
} }
if (current_music->times != 0) if (current_music->times != 0) {
{
if ((Uint32)SDL_GetAudioStreamAvailable(current_music->stream) < (current_music->length / 2)) { if ((Uint32)SDL_GetAudioStreamAvailable(current_music->stream) < (current_music->length / 2)) {
SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length); SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length);
} }
if (current_music->times > 0) current_music->times--; if (current_music->times > 0) current_music->times--;
} } else {
else
{
if (SDL_GetAudioStreamAvailable(current_music->stream) == 0) JA_StopMusic(); if (SDL_GetAudioStreamAvailable(current_music->stream) == 0) JA_StopMusic();
} }
} }
if (JA_soundEnabled) if (JA_soundEnabled) {
{
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) {
{ if (channels[i].times != 0) {
if (channels[i].times != 0)
{
if ((Uint32)SDL_GetAudioStreamAvailable(channels[i].stream) < (channels[i].sound->length / 2)) { if ((Uint32)SDL_GetAudioStreamAvailable(channels[i].stream) < (channels[i].sound->length / 2)) {
SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer, channels[i].sound->length); SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer, channels[i].sound->length);
if (channels[i].times > 0) channels[i].times--; if (channels[i].times > 0) channels[i].times--;
} }
} } else {
else
{
if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0) JA_StopChannel(i); if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0) JA_StopChannel(i);
} }
} }
} }
} }
inline void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channels) inline void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channels) {
{ #ifdef _DEBUG
#ifdef _DEBUG
SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG); SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
#endif #endif
JA_audioSpec = { format, num_channels, freq }; JA_audioSpec = {format, num_channels, freq};
if (sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); // Corregido: !sdlAudioDevice -> sdlAudioDevice if (sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); // Corregido: !sdlAudioDevice -> sdlAudioDevice
sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec); sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec);
if (sdlAudioDevice == 0) SDL_Log("Failed to initialize SDL audio!"); if (sdlAudioDevice == 0) SDL_Log("Failed to initialize SDL audio!");
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) channels[i].state = JA_CHANNEL_FREE; for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) channels[i].state = JA_CHANNEL_FREE;
for (int i = 0; i < JA_MAX_GROUPS; ++i) JA_soundVolume[i] = 0.5f; for (int i = 0; i < JA_MAX_GROUPS; ++i) JA_soundVolume[i] = 0.5f;
} }
inline void JA_Quit() inline void JA_Quit() {
{ if (sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); // Corregido: !sdlAudioDevice -> sdlAudioDevice
if (sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); // Corregido: !sdlAudioDevice -> sdlAudioDevice
sdlAudioDevice = 0; sdlAudioDevice = 0;
} }
// --- Music Functions --- // --- Music Functions ---
inline JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length) inline JA_Music_t* JA_LoadMusic(Uint8* buffer, Uint32 length) {
{ JA_Music_t* music = new JA_Music_t();
JA_Music_t *music = new JA_Music_t();
int chan, samplerate; int chan, samplerate;
short *output; short* output;
music->length = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &output) * chan * 2; music->length = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &output) * chan * 2;
music->spec.channels = chan; music->spec.channels = chan;
@@ -165,16 +157,15 @@ inline JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length)
return music; return music;
} }
inline JA_Music_t *JA_LoadMusic(const char* filename) inline 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. // [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"); FILE* f = fopen(filename, "rb");
if (!f) return NULL; // Añadida comprobación de apertura if (!f) return NULL; // Añadida comprobación de apertura
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
long fsize = ftell(f); long fsize = ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
Uint8 *buffer = (Uint8*)malloc(fsize + 1); Uint8* buffer = (Uint8*)malloc(fsize + 1);
if (!buffer) { // Añadida comprobación de malloc if (!buffer) { // Añadida comprobación de malloc
fclose(f); fclose(f);
return NULL; return NULL;
} }
@@ -185,8 +176,8 @@ inline JA_Music_t *JA_LoadMusic(const char* filename)
} }
fclose(f); fclose(f);
JA_Music_t *music = JA_LoadMusic(buffer, fsize); JA_Music_t* music = JA_LoadMusic(buffer, fsize);
if (music) { // Comprobar que JA_LoadMusic tuvo éxito if (music) { // Comprobar que JA_LoadMusic tuvo éxito
music->filename = (char*)malloc(strlen(filename) + 1); music->filename = (char*)malloc(strlen(filename) + 1);
if (music->filename) { if (music->filename) {
strcpy(music->filename, filename); strcpy(music->filename, filename);
@@ -198,9 +189,8 @@ inline JA_Music_t *JA_LoadMusic(const char* filename)
return music; return music;
} }
inline void JA_PlayMusic(JA_Music_t *music, const int loop = -1) inline void JA_PlayMusic(JA_Music_t* music, const int loop = -1) {
{ if (!JA_musicEnabled || !music) return; // Añadida comprobación de music
if (!JA_musicEnabled || !music) return; // Añadida comprobación de music
JA_StopMusic(); JA_StopMusic();
@@ -210,7 +200,7 @@ inline void JA_PlayMusic(JA_Music_t *music, const int loop = -1)
current_music->times = loop; current_music->times = loop;
current_music->stream = SDL_CreateAudioStream(&current_music->spec, &JA_audioSpec); current_music->stream = SDL_CreateAudioStream(&current_music->spec, &JA_audioSpec);
if (!current_music->stream) { // Comprobar creación de stream if (!current_music->stream) { // Comprobar creación de stream
SDL_Log("Failed to create audio stream!"); SDL_Log("Failed to create audio stream!");
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
return; return;
@@ -220,33 +210,29 @@ inline void JA_PlayMusic(JA_Music_t *music, const int loop = -1)
if (!SDL_BindAudioStream(sdlAudioDevice, current_music->stream)) printf("[ERROR] SDL_BindAudioStream failed!\n"); if (!SDL_BindAudioStream(sdlAudioDevice, current_music->stream)) printf("[ERROR] SDL_BindAudioStream failed!\n");
} }
inline char *JA_GetMusicFilename(JA_Music_t *music = nullptr) inline char* JA_GetMusicFilename(JA_Music_t* music = nullptr) {
{
if (!music) music = current_music; if (!music) music = current_music;
if (!music) return nullptr; // Añadida comprobación if (!music) return nullptr; // Añadida comprobación
return music->filename; return music->filename;
} }
inline void JA_PauseMusic() inline void JA_PauseMusic() {
{
if (!JA_musicEnabled) return; if (!JA_musicEnabled) return;
if (!current_music || current_music->state != JA_MUSIC_PLAYING) return; // Comprobación mejorada if (!current_music || current_music->state != JA_MUSIC_PLAYING) return; // Comprobación mejorada
current_music->state = JA_MUSIC_PAUSED; current_music->state = JA_MUSIC_PAUSED;
SDL_UnbindAudioStream(current_music->stream); SDL_UnbindAudioStream(current_music->stream);
} }
inline void JA_ResumeMusic() inline void JA_ResumeMusic() {
{
if (!JA_musicEnabled) return; if (!JA_musicEnabled) return;
if (!current_music || current_music->state != JA_MUSIC_PAUSED) return; // Comprobación mejorada if (!current_music || current_music->state != JA_MUSIC_PAUSED) return; // Comprobación mejorada
current_music->state = JA_MUSIC_PLAYING; current_music->state = JA_MUSIC_PLAYING;
SDL_BindAudioStream(sdlAudioDevice, current_music->stream); SDL_BindAudioStream(sdlAudioDevice, current_music->stream);
} }
inline void JA_StopMusic() inline void JA_StopMusic() {
{
if (!current_music || current_music->state == JA_MUSIC_INVALID || current_music->state == JA_MUSIC_STOPPED) return; if (!current_music || current_music->state == JA_MUSIC_INVALID || current_music->state == JA_MUSIC_STOPPED) return;
current_music->pos = 0; current_music->pos = 0;
@@ -258,8 +244,7 @@ inline void JA_StopMusic()
// No liberamos filename aquí, se debería liberar en JA_DeleteMusic // No liberamos filename aquí, se debería liberar en JA_DeleteMusic
} }
inline void JA_FadeOutMusic(const int milliseconds) inline void JA_FadeOutMusic(const int milliseconds) {
{
if (!JA_musicEnabled) return; if (!JA_musicEnabled) return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return; if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
@@ -269,16 +254,14 @@ inline void JA_FadeOutMusic(const int milliseconds)
fade_initial_volume = JA_musicVolume; fade_initial_volume = JA_musicVolume;
} }
inline JA_Music_state JA_GetMusicState() inline JA_Music_state JA_GetMusicState() {
{
if (!JA_musicEnabled) return JA_MUSIC_DISABLED; if (!JA_musicEnabled) return JA_MUSIC_DISABLED;
if (!current_music) return JA_MUSIC_INVALID; if (!current_music) return JA_MUSIC_INVALID;
return current_music->state; return current_music->state;
} }
inline void JA_DeleteMusic(JA_Music_t *music) inline void JA_DeleteMusic(JA_Music_t* music) {
{
if (!music) return; if (!music) return;
if (current_music == music) { if (current_music == music) {
JA_StopMusic(); JA_StopMusic();
@@ -286,12 +269,11 @@ inline void JA_DeleteMusic(JA_Music_t *music)
} }
SDL_free(music->buffer); SDL_free(music->buffer);
if (music->stream) SDL_DestroyAudioStream(music->stream); if (music->stream) SDL_DestroyAudioStream(music->stream);
free(music->filename); // filename se libera aquí free(music->filename); // filename se libera aquí
delete music; delete music;
} }
inline float JA_SetMusicVolume(float volume) inline float JA_SetMusicVolume(float volume) {
{
JA_musicVolume = SDL_clamp(volume, 0.0f, 1.0f); JA_musicVolume = SDL_clamp(volume, 0.0f, 1.0f);
if (current_music && current_music->stream) { if (current_music && current_music->stream) {
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume); SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
@@ -299,43 +281,37 @@ inline float JA_SetMusicVolume(float volume)
return JA_musicVolume; return JA_musicVolume;
} }
inline void JA_SetMusicPosition(float value) inline void JA_SetMusicPosition(float value) {
{
if (!current_music) return; if (!current_music) return;
current_music->pos = value * current_music->spec.freq; current_music->pos = value * current_music->spec.freq;
// Nota: Esta implementación de 'pos' no parece usarse en JA_Update para // Nota: Esta implementación de 'pos' no parece usarse en JA_Update para
// el streaming. El streaming siempre parece empezar desde el principio. // el streaming. El streaming siempre parece empezar desde el principio.
} }
inline float JA_GetMusicPosition() inline float JA_GetMusicPosition() {
{
if (!current_music) return 0; if (!current_music) return 0;
return float(current_music->pos) / float(current_music->spec.freq); return float(current_music->pos) / float(current_music->spec.freq);
// Nota: Ver `JA_SetMusicPosition` // Nota: Ver `JA_SetMusicPosition`
} }
inline void JA_EnableMusic(const bool value) inline void JA_EnableMusic(const bool value) {
{
if (!value && current_music && (current_music->state == JA_MUSIC_PLAYING)) JA_StopMusic(); if (!value && current_music && (current_music->state == JA_MUSIC_PLAYING)) JA_StopMusic();
JA_musicEnabled = value; JA_musicEnabled = value;
} }
// --- Sound Functions --- // --- Sound Functions ---
inline JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length) inline 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;
// Nota: spec se queda con los valores por defecto. // Nota: spec se queda con los valores por defecto.
return sound; return sound;
} }
inline JA_Sound_t *JA_LoadSound(uint8_t* buffer, uint32_t size) inline JA_Sound_t* JA_LoadSound(uint8_t* buffer, uint32_t size) {
{ JA_Sound_t* sound = new JA_Sound_t();
JA_Sound_t *sound = new JA_Sound_t();
if (!SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &sound->buffer, &sound->length)) { if (!SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &sound->buffer, &sound->length)) {
SDL_Log("Failed to load WAV from memory: %s", SDL_GetError()); SDL_Log("Failed to load WAV from memory: %s", SDL_GetError());
delete sound; delete sound;
@@ -344,9 +320,8 @@ inline JA_Sound_t *JA_LoadSound(uint8_t* buffer, uint32_t size)
return sound; return sound;
} }
inline JA_Sound_t *JA_LoadSound(const char* filename) inline JA_Sound_t* JA_LoadSound(const char* filename) {
{ JA_Sound_t* sound = new JA_Sound_t();
JA_Sound_t *sound = new JA_Sound_t();
if (!SDL_LoadWAV(filename, &sound->spec, &sound->buffer, &sound->length)) { if (!SDL_LoadWAV(filename, &sound->spec, &sound->buffer, &sound->length)) {
SDL_Log("Failed to load WAV file: %s", SDL_GetError()); SDL_Log("Failed to load WAV file: %s", SDL_GetError());
delete sound; delete sound;
@@ -355,8 +330,7 @@ inline JA_Sound_t *JA_LoadSound(const char* filename)
return sound; return sound;
} }
inline int JA_PlaySound(JA_Sound_t *sound, const int loop = 0, const int group = 0) inline int JA_PlaySound(JA_Sound_t* sound, const int loop = 0, const int group = 0) {
{
if (!JA_soundEnabled || !sound) return -1; if (!JA_soundEnabled || !sound) return -1;
int channel = 0; int channel = 0;
@@ -369,17 +343,16 @@ inline int JA_PlaySound(JA_Sound_t *sound, const int loop = 0, const int group =
return JA_PlaySoundOnChannel(sound, channel, loop, group); return JA_PlaySoundOnChannel(sound, channel, loop, group);
} }
inline int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop, const int group) inline int JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop, const int group) {
{
if (!JA_soundEnabled || !sound) return -1; if (!JA_soundEnabled || !sound) return -1;
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return -1; if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return -1;
JA_StopChannel(channel); // Detiene y limpia el canal si estaba en uso JA_StopChannel(channel); // Detiene y limpia el canal si estaba en uso
channels[channel].sound = sound; channels[channel].sound = sound;
channels[channel].times = loop; channels[channel].times = loop;
channels[channel].pos = 0; channels[channel].pos = 0;
channels[channel].group = group; // Asignar grupo channels[channel].group = group; // Asignar grupo
channels[channel].state = JA_CHANNEL_PLAYING; channels[channel].state = JA_CHANNEL_PLAYING;
channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec); channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec);
@@ -396,8 +369,7 @@ inline int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int
return channel; return channel;
} }
inline void JA_DeleteSound(JA_Sound_t *sound) inline void JA_DeleteSound(JA_Sound_t* sound) {
{
if (!sound) return; if (!sound) return;
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);
@@ -406,56 +378,42 @@ inline void JA_DeleteSound(JA_Sound_t *sound)
delete sound; delete sound;
} }
inline void JA_PauseChannel(const int channel) inline void JA_PauseChannel(const int channel) {
{
if (!JA_soundEnabled) return; if (!JA_soundEnabled) 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) if (channels[i].state == JA_CHANNEL_PLAYING) {
{
channels[i].state = JA_CHANNEL_PAUSED; channels[i].state = JA_CHANNEL_PAUSED;
SDL_UnbindAudioStream(channels[i].stream); SDL_UnbindAudioStream(channels[i].stream);
} }
} } 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) {
{
if (channels[channel].state == JA_CHANNEL_PLAYING)
{
channels[channel].state = JA_CHANNEL_PAUSED; channels[channel].state = JA_CHANNEL_PAUSED;
SDL_UnbindAudioStream(channels[channel].stream); SDL_UnbindAudioStream(channels[channel].stream);
} }
} }
} }
inline void JA_ResumeChannel(const int channel) inline void JA_ResumeChannel(const int channel) {
{
if (!JA_soundEnabled) return; if (!JA_soundEnabled) 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) if (channels[i].state == JA_CHANNEL_PAUSED) {
{
channels[i].state = JA_CHANNEL_PLAYING; channels[i].state = JA_CHANNEL_PLAYING;
SDL_BindAudioStream(sdlAudioDevice, channels[i].stream); SDL_BindAudioStream(sdlAudioDevice, channels[i].stream);
} }
} } 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) {
{
if (channels[channel].state == JA_CHANNEL_PAUSED)
{
channels[channel].state = JA_CHANNEL_PLAYING; channels[channel].state = JA_CHANNEL_PLAYING;
SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream); SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream);
} }
} }
} }
inline void JA_StopChannel(const int channel) inline void JA_StopChannel(const int channel) {
{ 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_FREE) { if (channels[i].state != JA_CHANNEL_FREE) {
if (channels[i].stream) SDL_DestroyAudioStream(channels[i].stream); if (channels[i].stream) SDL_DestroyAudioStream(channels[i].stream);
@@ -465,9 +423,7 @@ inline void JA_StopChannel(const int channel)
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)
{
if (channels[channel].state != JA_CHANNEL_FREE) { if (channels[channel].state != JA_CHANNEL_FREE) {
if (channels[channel].stream) SDL_DestroyAudioStream(channels[channel].stream); if (channels[channel].stream) SDL_DestroyAudioStream(channels[channel].stream);
channels[channel].stream = nullptr; channels[channel].stream = nullptr;
@@ -478,15 +434,14 @@ inline void JA_StopChannel(const int channel)
} }
} }
inline JA_Channel_state JA_GetChannelState(const int channel) inline JA_Channel_state JA_GetChannelState(const int channel) {
{
if (!JA_soundEnabled) return JA_SOUND_DISABLED; if (!JA_soundEnabled) return JA_SOUND_DISABLED;
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID; if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID;
return channels[channel].state; return channels[channel].state;
} }
inline float JA_SetSoundVolume(float volume, const int group = -1) // -1 para todos los grupos inline float JA_SetSoundVolume(float volume, const int group = -1) // -1 para todos los grupos
{ {
const float v = SDL_clamp(volume, 0.0f, 1.0f); const float v = SDL_clamp(volume, 0.0f, 1.0f);
@@ -497,7 +452,7 @@ inline float JA_SetSoundVolume(float volume, const int group = -1) // -1 para to
} else if (group >= 0 && group < JA_MAX_GROUPS) { } else if (group >= 0 && group < JA_MAX_GROUPS) {
JA_soundVolume[group] = v; JA_soundVolume[group] = v;
} else { } else {
return v; // Grupo inválido return v; // Grupo inválido
} }
// Aplicar volumen a canales activos // Aplicar volumen a canales activos
@@ -505,7 +460,7 @@ inline float JA_SetSoundVolume(float volume, const int group = -1) // -1 para to
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)) {
if (group == -1 || channels[i].group == group) { if (group == -1 || channels[i].group == group) {
if (channels[i].stream) { if (channels[i].stream) {
SDL_SetAudioStreamGain(channels[i].stream, JA_soundVolume[channels[i].group]); SDL_SetAudioStreamGain(channels[i].stream, JA_soundVolume[channels[i].group]);
} }
} }
} }
@@ -513,17 +468,15 @@ inline float JA_SetSoundVolume(float volume, const int group = -1) // -1 para to
return v; return v;
} }
inline void JA_EnableSound(const bool value) inline void JA_EnableSound(const bool value) {
{
if (!value) { if (!value) {
JA_StopChannel(-1); // Detener todos los canales JA_StopChannel(-1); // Detener todos los canales
} }
JA_soundEnabled = value; JA_soundEnabled = value;
} }
inline float JA_SetVolume(float volume) inline float JA_SetVolume(float volume) {
{
float v = JA_SetMusicVolume(volume); float v = JA_SetMusicVolume(volume);
JA_SetSoundVolume(v, -1); // Aplicar a todos los grupos de sonido JA_SetSoundVolume(v, -1); // Aplicar a todos los grupos de sonido
return v; return v;
} }

View File

@@ -30,28 +30,28 @@ Input::Input(std::string game_controller_db_path)
// Inicializar bindings del teclado // Inicializar bindings del teclado
keyboard_.bindings = { keyboard_.bindings = {
// Movimiento del jugador // Movimiento del jugador
{Action::LEFT, KeyState{SDL_SCANCODE_LEFT}}, {Action::LEFT, KeyState{.scancode = SDL_SCANCODE_LEFT}},
{Action::RIGHT, KeyState{SDL_SCANCODE_RIGHT}}, {Action::RIGHT, KeyState{.scancode = SDL_SCANCODE_RIGHT}},
{Action::JUMP, KeyState{SDL_SCANCODE_UP}}, {Action::JUMP, KeyState{.scancode = SDL_SCANCODE_UP}},
// Inputs de control // Inputs de control
{Action::ACCEPT, KeyState{SDL_SCANCODE_RETURN}}, {Action::ACCEPT, KeyState{.scancode = SDL_SCANCODE_RETURN}},
{Action::CANCEL, KeyState{SDL_SCANCODE_ESCAPE}}, {Action::CANCEL, KeyState{.scancode = SDL_SCANCODE_ESCAPE}},
{Action::EXIT, KeyState{SDL_SCANCODE_ESCAPE}}, {Action::EXIT, KeyState{.scancode = SDL_SCANCODE_ESCAPE}},
// Inputs de sistema // Inputs de sistema
{Action::WINDOW_DEC_ZOOM, KeyState{SDL_SCANCODE_F1}}, {Action::WINDOW_DEC_ZOOM, KeyState{.scancode = SDL_SCANCODE_F1}},
{Action::WINDOW_INC_ZOOM, KeyState{SDL_SCANCODE_F2}}, {Action::WINDOW_INC_ZOOM, KeyState{.scancode = SDL_SCANCODE_F2}},
{Action::TOGGLE_FULLSCREEN, KeyState{SDL_SCANCODE_F3}}, {Action::TOGGLE_FULLSCREEN, KeyState{.scancode = SDL_SCANCODE_F3}},
{Action::TOGGLE_SHADERS, KeyState{SDL_SCANCODE_F4}}, {Action::TOGGLE_SHADERS, KeyState{.scancode = SDL_SCANCODE_F4}},
{Action::NEXT_PALETTE, KeyState{SDL_SCANCODE_F5}}, {Action::NEXT_PALETTE, KeyState{.scancode = SDL_SCANCODE_F5}},
{Action::PREVIOUS_PALETTE, KeyState{SDL_SCANCODE_F6}}, {Action::PREVIOUS_PALETTE, KeyState{.scancode = SDL_SCANCODE_F6}},
{Action::TOGGLE_INTEGER_SCALE, KeyState{SDL_SCANCODE_F7}}, {Action::TOGGLE_INTEGER_SCALE, KeyState{.scancode = SDL_SCANCODE_F7}},
{Action::TOGGLE_MUSIC, KeyState{SDL_SCANCODE_F8}}, {Action::TOGGLE_MUSIC, KeyState{.scancode = SDL_SCANCODE_F8}},
{Action::TOGGLE_BORDER, KeyState{SDL_SCANCODE_F9}}, {Action::TOGGLE_BORDER, KeyState{.scancode = SDL_SCANCODE_F9}},
{Action::TOGGLE_VSYNC, KeyState{SDL_SCANCODE_F10}}, {Action::TOGGLE_VSYNC, KeyState{.scancode = SDL_SCANCODE_F10}},
{Action::PAUSE, KeyState{SDL_SCANCODE_F11}}, {Action::PAUSE, KeyState{.scancode = SDL_SCANCODE_F11}},
{Action::TOGGLE_DEBUG, KeyState{SDL_SCANCODE_F12}}}; {Action::TOGGLE_DEBUG, KeyState{.scancode = SDL_SCANCODE_F12}}};
initSDLGamePad(); // Inicializa el subsistema SDL_INIT_GAMEPAD initSDLGamePad(); // Inicializa el subsistema SDL_INIT_GAMEPAD
} }

View File

@@ -41,15 +41,15 @@ class Input {
}; };
struct Keyboard { struct Keyboard {
std::unordered_map<Action, KeyState> bindings{}; // Mapa de acciones a estados de tecla std::unordered_map<Action, KeyState> bindings; // Mapa de acciones a estados de tecla
}; };
struct Gamepad { struct Gamepad {
SDL_Gamepad* pad{nullptr}; // Puntero al gamepad SDL SDL_Gamepad* pad{nullptr}; // Puntero al gamepad SDL
SDL_JoystickID instance_id{0}; // ID de instancia del joystick SDL_JoystickID instance_id{0}; // ID de instancia del joystick
std::string name{}; // Nombre del gamepad std::string name; // Nombre del gamepad
std::string path{}; // Ruta del dispositivo std::string path; // Ruta del dispositivo
std::unordered_map<Action, ButtonState> bindings{}; // Mapa de acciones a estados de botón std::unordered_map<Action, ButtonState> bindings; // Mapa de acciones a estados de botón
explicit Gamepad(SDL_Gamepad* gamepad) explicit Gamepad(SDL_Gamepad* gamepad)
: pad(gamepad), : pad(gamepad),
@@ -58,9 +58,9 @@ class Input {
path(std::string(SDL_GetGamepadPath(pad))), path(std::string(SDL_GetGamepadPath(pad))),
bindings{ bindings{
// Movimiento del jugador // Movimiento del jugador
{Action::LEFT, ButtonState{static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_LEFT)}}, {Action::LEFT, ButtonState{.button = static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_LEFT)}},
{Action::RIGHT, ButtonState{static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_RIGHT)}}, {Action::RIGHT, ButtonState{.button = static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_RIGHT)}},
{Action::JUMP, ButtonState{static_cast<int>(SDL_GAMEPAD_BUTTON_WEST)}}} {} {Action::JUMP, ButtonState{.button = static_cast<int>(SDL_GAMEPAD_BUTTON_WEST)}}} {}
~Gamepad() { ~Gamepad() {
if (pad != nullptr) { if (pad != nullptr) {
@@ -134,7 +134,7 @@ class Input {
// --- Variables miembro --- // --- Variables miembro ---
static Input* instance; // Instancia única del singleton static Input* instance; // Instancia única del singleton
Gamepads gamepads_{}; // Lista de gamepads conectados Gamepads gamepads_; // Lista de gamepads conectados
Keyboard keyboard_{}; // Estado del teclado Keyboard keyboard_{}; // Estado del teclado
std::string gamepad_mappings_file_{}; // Ruta al archivo de mappings std::string gamepad_mappings_file_; // Ruta al archivo de mappings
}; };

View File

@@ -71,10 +71,10 @@ class Screen {
private: private:
// Estructuras // Estructuras
struct DisplayMonitor { struct DisplayMonitor {
std::string name{}; std::string name;
int width{0}; int width{0};
int height{0}; int height{0};
int refresh_rate{0}; int refresh_rate{0};
}; };
struct FPS { struct FPS {

View File

@@ -54,7 +54,7 @@ auto SurfaceAnimatedSprite::loadAnimationsFromYAML(const std::string& file_path,
// --- Parse global configuration --- // --- Parse global configuration ---
if (yaml.contains("tileSetFile")) { if (yaml.contains("tileSetFile")) {
std::string tile_set_file = yaml["tileSetFile"].get_value<std::string>(); auto tile_set_file = yaml["tileSetFile"].get_value<std::string>();
surface = Resource::Cache::get()->getSurface(tile_set_file); surface = Resource::Cache::get()->getSurface(tile_set_file);
} }
@@ -137,7 +137,7 @@ SurfaceAnimatedSprite::SurfaceAnimatedSprite(const AnimationResource& cached_dat
// --- Parse global configuration --- // --- Parse global configuration ---
if (yaml.contains("tileSetFile")) { if (yaml.contains("tileSetFile")) {
std::string tile_set_file = yaml["tileSetFile"].get_value<std::string>(); auto tile_set_file = yaml["tileSetFile"].get_value<std::string>();
// Ahora SÍ podemos acceder al cache (ya está completamente cargado) // Ahora SÍ podemos acceder al cache (ya está completamente cargado)
surface_ = Resource::Cache::get()->getSurface(tile_set_file); surface_ = Resource::Cache::get()->getSurface(tile_set_file);
} }

View File

@@ -18,7 +18,7 @@ class SurfaceAnimatedSprite : public SurfaceMovingSprite {
// Estructura pública de datos de animación // Estructura pública de datos de animación
struct AnimationData { struct AnimationData {
std::string name{}; // Nombre de la animacion std::string name; // Nombre de la animacion
std::vector<SDL_FRect> frames; // Cada uno de los frames que componen la animación std::vector<SDL_FRect> frames; // Cada uno de los frames que componen la animación
float speed{0.083F}; // Velocidad de la animación (segundos por frame) float speed{0.083F}; // Velocidad de la animación (segundos por frame)
int loop{0}; // Indica a que frame vuelve la animación al terminar. -1 para que no vuelva int loop{0}; // Indica a que frame vuelve la animación al terminar. -1 para que no vuelva

View File

@@ -55,14 +55,14 @@ void Player::update(float delta_time) {
// Comprueba las entradas y modifica variables // Comprueba las entradas y modifica variables
void Player::handleInput() { void Player::handleInput() {
if (Input::get()->checkAction(InputAction::LEFT)) { if (Input::get()->checkAction(InputAction::LEFT)) {
wannaGo = Direction::LEFT; wanna_go_ = Direction::LEFT;
} else if (Input::get()->checkAction(InputAction::RIGHT)) { } else if (Input::get()->checkAction(InputAction::RIGHT)) {
wannaGo = Direction::RIGHT; wanna_go_ = Direction::RIGHT;
} else { } else {
wannaGo = Direction::NONE; wanna_go_ = Direction::NONE;
} }
wannaJump = Input::get()->checkAction(InputAction::JUMP); wanna_jump_ = Input::get()->checkAction(InputAction::JUMP);
} }
// La lógica de movimiento está distribuida en move // La lógica de movimiento está distribuida en move
@@ -89,7 +89,7 @@ void Player::move(float delta_time) {
} }
void Player::handleConveyorBelts() { void Player::handleConveyorBelts() {
if (!auto_movement_ and isOnConveyorBelt() and wannaGo == Direction::NONE) { if (!auto_movement_ and isOnConveyorBelt() and wanna_go_ == Direction::NONE) {
auto_movement_ = true; auto_movement_ = true;
} }
@@ -171,7 +171,7 @@ void Player::updateOnGround(float delta_time) {
handleShouldFall(); // Verifica si debe caer (no tiene suelo) handleShouldFall(); // Verifica si debe caer (no tiene suelo)
// Verifica si el jugador quiere saltar // Verifica si el jugador quiere saltar
if (wannaJump) { transitionToState(State::JUMPING); } if (wanna_jump_) { transitionToState(State::JUMPING); }
} }
// Actualización lógica del estado ON_SLOPE // Actualización lógica del estado ON_SLOPE
@@ -182,7 +182,7 @@ void Player::updateOnSlope(float delta_time) {
// todas las condiciones de salida de la rampa (out of bounds, transición a superficie plana) // todas las condiciones de salida de la rampa (out of bounds, transición a superficie plana)
// Verifica si el jugador quiere saltar // Verifica si el jugador quiere saltar
if (wannaJump) { transitionToState(State::JUMPING); } if (wanna_jump_) { transitionToState(State::JUMPING); }
} }
// Actualización lógica del estado JUMPING // Actualización lógica del estado JUMPING
@@ -200,7 +200,7 @@ void Player::updateFalling(float delta_time) {
// Movimiento físico del estado ON_GROUND // Movimiento físico del estado ON_GROUND
void Player::moveOnGround(float delta_time) { void Player::moveOnGround(float delta_time) {
// Determinama cuál debe ser la velocidad a partir de automovement o de wannaGo // Determinama cuál debe ser la velocidad a partir de automovement o de wanna_go_
updateVelocity(); updateVelocity();
if (vx_ == 0.0F) { return; } if (vx_ == 0.0F) { return; }
@@ -229,7 +229,7 @@ void Player::moveOnGround(float delta_time) {
// Movimiento físico del estado ON_SLOPE // Movimiento físico del estado ON_SLOPE
void Player::moveOnSlope(float delta_time) { void Player::moveOnSlope(float delta_time) {
// Determinama cuál debe ser la velocidad a partir de automovement o de wannaGo // Determinama cuál debe ser la velocidad a partir de automovement o de wanna_go_
updateVelocity(); updateVelocity();
if (vx_ == 0.0F) { return; } if (vx_ == 0.0F) { return; }
@@ -636,35 +636,35 @@ void Player::initSounds() {
// Implementación de JumpSoundController::start // Implementación de JumpSoundController::start
void Player::JumpSoundController::start() { void Player::JumpSoundController::start() {
current_index_ = 0; current_index = 0;
elapsed_time_ = 0.0F; elapsed_time = 0.0F;
active_ = true; active = true;
} }
// Implementación de JumpSoundController::reset // Implementación de JumpSoundController::reset
void Player::JumpSoundController::reset() { void Player::JumpSoundController::reset() {
active_ = false; active = false;
current_index_ = 0; current_index = 0;
elapsed_time_ = 0.0F; elapsed_time = 0.0F;
} }
// Implementación de JumpSoundController::shouldPlay // Implementación de JumpSoundController::shouldPlay
auto Player::JumpSoundController::shouldPlay(float delta_time, size_t& out_index) -> bool { auto Player::JumpSoundController::shouldPlay(float delta_time, size_t& out_index) -> bool {
if (!active_) { if (!active) {
return false; return false;
} }
// Acumula el tiempo transcurrido durante el salto // Acumula el tiempo transcurrido durante el salto
elapsed_time_ += delta_time; elapsed_time += delta_time;
// Calcula qué sonido debería estar sonando según el tiempo // Calcula qué sonido debería estar sonando según el tiempo
size_t target_index = FIRST_SOUND + static_cast<size_t>(elapsed_time_ / SECONDS_PER_SOUND); size_t target_index = FIRST_SOUND + static_cast<size_t>(elapsed_time / SECONDS_PER_SOUND);
target_index = std::min(target_index, LAST_SOUND); target_index = std::min(target_index, LAST_SOUND);
// Reproduce si hemos avanzado a un nuevo sonido // Reproduce si hemos avanzado a un nuevo sonido
if (target_index > current_index_) { if (target_index > current_index) {
current_index_ = target_index; current_index = target_index;
out_index = current_index_; out_index = current_index;
return true; return true;
} }
@@ -673,42 +673,42 @@ auto Player::JumpSoundController::shouldPlay(float delta_time, size_t& out_index
// Implementación de FallSoundController::start // Implementación de FallSoundController::start
void Player::FallSoundController::start(float start_y) { void Player::FallSoundController::start(float start_y) {
current_index_ = 0; current_index = 0;
distance_traveled_ = 0.0F; distance_traveled = 0.0F;
last_y_ = start_y; last_y = start_y;
active_ = true; active = true;
} }
// Implementación de FallSoundController::reset // Implementación de FallSoundController::reset
void Player::FallSoundController::reset() { void Player::FallSoundController::reset() {
active_ = false; active = false;
current_index_ = 0; current_index = 0;
distance_traveled_ = 0.0F; distance_traveled = 0.0F;
} }
// Implementación de FallSoundController::shouldPlay // Implementación de FallSoundController::shouldPlay
auto Player::FallSoundController::shouldPlay(float delta_time, float current_y, size_t& out_index) -> bool { auto Player::FallSoundController::shouldPlay(float delta_time, float current_y, size_t& out_index) -> bool {
(void)delta_time; // No usado actualmente, pero recibido por consistencia (void)delta_time; // No usado actualmente, pero recibido por consistencia
if (!active_) { if (!active) {
return false; return false;
} }
// Acumula la distancia recorrida (solo hacia abajo) // Acumula la distancia recorrida (solo hacia abajo)
if (current_y > last_y_) { if (current_y > last_y) {
distance_traveled_ += (current_y - last_y_); distance_traveled += (current_y - last_y);
} }
last_y_ = current_y; last_y = current_y;
// Calcula qué sonido debería estar sonando según el intervalo // Calcula qué sonido debería estar sonando según el intervalo
size_t target_index = FIRST_SOUND + static_cast<size_t>(distance_traveled_ / PIXELS_PER_SOUND); size_t target_index = FIRST_SOUND + static_cast<size_t>(distance_traveled / PIXELS_PER_SOUND);
// El sonido a reproducir se limita a LAST_SOUND (13), pero el índice interno sigue creciendo // El sonido a reproducir se limita a LAST_SOUND (13), pero el índice interno sigue creciendo
size_t sound_to_play = std::min(target_index, LAST_SOUND); size_t sound_to_play = std::min(target_index, LAST_SOUND);
// Reproduce si hemos avanzado a un nuevo índice (permite repetición de sonido 13) // Reproduce si hemos avanzado a un nuevo índice (permite repetición de sonido 13)
if (target_index > current_index_) { if (target_index > current_index) {
current_index_ = target_index; // Guardamos el índice real (puede ser > LAST_SOUND) current_index = target_index; // Guardamos el índice real (puede ser > LAST_SOUND)
out_index = sound_to_play; // Pero reproducimos LAST_SOUND cuando corresponde out_index = sound_to_play; // Pero reproducimos LAST_SOUND cuando corresponde
return true; return true;
} }
@@ -768,7 +768,7 @@ void Player::updateVelocity() {
sprite_->setFlip(vx_ < 0.0F ? Flip::LEFT : Flip::RIGHT); sprite_->setFlip(vx_ < 0.0F ? Flip::LEFT : Flip::RIGHT);
} else { } else {
// El jugador tiene el control // El jugador tiene el control
switch (wannaGo) { switch (wanna_go_) {
case Direction::LEFT: case Direction::LEFT:
vx_ = -HORIZONTAL_VELOCITY; vx_ = -HORIZONTAL_VELOCITY;
sprite_->setFlip(Flip::LEFT); sprite_->setFlip(Flip::LEFT);

View File

@@ -61,13 +61,13 @@ class Player {
static constexpr size_t LAST_SOUND = 17; // Último sonido a reproducir (índice 17) static constexpr size_t LAST_SOUND = 17; // Último sonido a reproducir (índice 17)
static constexpr float SECONDS_PER_SOUND = JUMP_DURATION / (LAST_SOUND - FIRST_SOUND + 1); static constexpr float SECONDS_PER_SOUND = JUMP_DURATION / (LAST_SOUND - FIRST_SOUND + 1);
size_t current_index_ = 0; // Índice del sonido actual size_t current_index = 0; // Índice del sonido actual
float elapsed_time_ = 0.0F; // Tiempo transcurrido durante el salto float elapsed_time = 0.0F; // Tiempo transcurrido durante el salto
bool active_ = false; // Indica si el controlador está activo bool active = false; // Indica si el controlador está activo
void start(); // Inicia el controlador void start(); // Inicia el controlador
void reset(); // Resetea el controlador void reset(); // Resetea el controlador
bool shouldPlay(float delta_time, size_t& out_index); // Comprueba si debe reproducir un sonido auto shouldPlay(float delta_time, size_t& out_index) -> bool; // Comprueba si debe reproducir un sonido
}; };
struct FallSoundController { struct FallSoundController {
@@ -75,14 +75,14 @@ class Player {
static constexpr size_t FIRST_SOUND = 1; // Primer sonido a reproducir (índice 1) static constexpr size_t FIRST_SOUND = 1; // Primer sonido a reproducir (índice 1)
static constexpr size_t LAST_SOUND = 13; // Último sonido a reproducir (índice 13) static constexpr size_t LAST_SOUND = 13; // Último sonido a reproducir (índice 13)
size_t current_index_ = 0; // Índice del sonido actual size_t current_index = 0; // Índice del sonido actual
float distance_traveled_ = 0.0F; // Distancia acumulada durante la caída float distance_traveled = 0.0F; // Distancia acumulada durante la caída
float last_y_ = 0.0F; // Última posición Y registrada float last_y = 0.0F; // Última posición Y registrada
bool active_ = false; // Indica si el controlador está activo bool active = false; // Indica si el controlador está activo
void start(float start_y); // Inicia el controlador void start(float start_y); // Inicia el controlador
void reset(); // Resetea el controlador void reset(); // Resetea el controlador
bool shouldPlay(float delta_time, float current_y, size_t& out_index); // Comprueba si debe reproducir un sonido auto shouldPlay(float delta_time, float current_y, size_t& out_index) -> bool; // Comprueba si debe reproducir un sonido
}; };
// --- Constructor y Destructor --- // --- Constructor y Destructor ---
@@ -97,7 +97,7 @@ class Player {
void switchBorders(); // Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla void switchBorders(); // Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla
auto getRect() -> SDL_FRect { return {x_, y_, WIDTH, HEIGHT}; } // Obtiene el rectangulo que delimita al jugador auto getRect() -> SDL_FRect { return {x_, y_, WIDTH, HEIGHT}; } // Obtiene el rectangulo que delimita al jugador
auto getCollider() -> SDL_FRect& { return collider_box_; } // Obtiene el rectangulo de colision del jugador auto getCollider() -> SDL_FRect& { return collider_box_; } // Obtiene el rectangulo de colision del jugador
auto getSpawnParams() -> SpawnData { return {x_, y_, vx_, vy_, last_grounded_position_, state_, sprite_->getFlip()}; } // Obtiene el estado de reaparición del jugador auto getSpawnParams() -> SpawnData { return {.x = x_, .y = y_, .vx = vx_, .vy = vy_, .last_grounded_position = last_grounded_position_, .state = state_, .flip = sprite_->getFlip()}; } // Obtiene el estado de reaparición del jugador
void setColor(); // Establece el color del jugador void setColor(); // Establece el color del jugador
void setRoom(std::shared_ptr<Room> room) { room_ = std::move(room); } // Establece la habitación en la que se encuentra el jugador void setRoom(std::shared_ptr<Room> room) { room_ = std::move(room); } // Establece la habitación en la que se encuentra el jugador
[[nodiscard]] auto isAlive() const -> bool { return is_alive_; } // Comprueba si el jugador esta vivo [[nodiscard]] auto isAlive() const -> bool { return is_alive_; } // Comprueba si el jugador esta vivo
@@ -120,8 +120,8 @@ class Player {
float vx_ = 0.0F; // Velocidad/desplazamiento del jugador en el eje X float vx_ = 0.0F; // Velocidad/desplazamiento del jugador en el eje X
float vy_ = 0.0F; // Velocidad/desplazamiento del jugador en el eje Y float vy_ = 0.0F; // Velocidad/desplazamiento del jugador en el eje Y
Direction wannaGo = Direction::NONE; Direction wanna_go_ = Direction::NONE;
bool wannaJump = false; bool wanna_jump_ = false;
// --- Variables de estado --- // --- Variables de estado ---
State state_ = State::ON_GROUND; // Estado en el que se encuentra el jugador. Util apara saber si está saltando o cayendo State state_ = State::ON_GROUND; // Estado en el que se encuentra el jugador. Util apara saber si está saltando o cayendo

View File

@@ -9,8 +9,8 @@ class Cheevos {
// Tipos anidados (públicos porque se usan en la interfaz) // Tipos anidados (públicos porque se usan en la interfaz)
struct Achievement { struct Achievement {
int id{0}; // Identificador del logro int id{0}; // Identificador del logro
std::string caption{}; // Texto con el nombre del logro std::string caption; // Texto con el nombre del logro
std::string description{}; // Texto que describe el logro std::string description; // Texto que describe el logro
int icon{0}; // Indice del icono a utilizar en la notificación int icon{0}; // Indice del icono a utilizar en la notificación
bool completed{false}; // Indica si se ha obtenido el logro bool completed{false}; // Indica si se ha obtenido el logro
bool obtainable{true}; // Indica si se puede obtener el logro bool obtainable{true}; // Indica si se puede obtener el logro

View File

@@ -44,8 +44,8 @@ class CollisionMap {
auto operator=(CollisionMap&&) -> CollisionMap& = delete; auto operator=(CollisionMap&&) -> CollisionMap& = delete;
// --- Queries de tipo de tile --- // --- Queries de tipo de tile ---
auto getTile(SDL_FPoint point) const -> Tile; // Devuelve el tipo de tile en un punto (pixel) [[nodiscard]] auto getTile(SDL_FPoint point) const -> Tile; // Devuelve el tipo de tile en un punto (pixel)
auto getTile(int index) const -> Tile; // Devuelve el tipo de tile en un índice del tilemap [[nodiscard]] auto getTile(int index) const -> Tile; // Devuelve el tipo de tile en un índice del tilemap
// --- Queries de colisión con superficies --- // --- Queries de colisión con superficies ---
auto checkRightSurfaces(const SDL_FRect& rect) -> int; // Colisión con paredes derechas (retorna X) auto checkRightSurfaces(const SDL_FRect& rect) -> int; // Colisión con paredes derechas (retorna X)
@@ -63,7 +63,7 @@ class CollisionMap {
auto checkLeftSlopes(const SDL_FPoint& p) -> bool; // Colisión punto con rampas izquierdas auto checkLeftSlopes(const SDL_FPoint& p) -> bool; // Colisión punto con rampas izquierdas
auto checkRightSlopes(const LineVertical& line) -> int; // Colisión línea con rampas derechas (retorna Y) auto checkRightSlopes(const LineVertical& line) -> int; // Colisión línea con rampas derechas (retorna Y)
auto checkRightSlopes(const SDL_FPoint& p) -> bool; // Colisión punto con rampas derechas auto checkRightSlopes(const SDL_FPoint& p) -> bool; // Colisión punto con rampas derechas
auto getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal*; // Obtiene puntero a slope en un punto [[nodiscard]] auto getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal*; // Obtiene puntero a slope en un punto
// --- Métodos estáticos --- // --- Métodos estáticos ---
static auto getTileSize() -> int { return TILE_SIZE; } // Tamaño del tile en pixels static auto getTileSize() -> int { return TILE_SIZE; } // Tamaño del tile en pixels

View File

@@ -23,15 +23,15 @@ class EnemyManager {
// Prohibir copia y movimiento para evitar duplicación accidental // Prohibir copia y movimiento para evitar duplicación accidental
EnemyManager(const EnemyManager&) = delete; EnemyManager(const EnemyManager&) = delete;
EnemyManager& operator=(const EnemyManager&) = delete; auto operator=(const EnemyManager&) -> EnemyManager& = delete;
EnemyManager(EnemyManager&&) = delete; EnemyManager(EnemyManager&&) = delete;
EnemyManager& operator=(EnemyManager&&) = delete; auto operator=(EnemyManager&&) -> EnemyManager& = delete;
// Gestión de enemigos // Gestión de enemigos
void addEnemy(std::shared_ptr<Enemy> enemy); // Añade un enemigo a la colección void addEnemy(std::shared_ptr<Enemy> enemy); // Añade un enemigo a la colección
void clear(); // Elimina todos los enemigos void clear(); // Elimina todos los enemigos
void removeLastEnemy(); // Elimina el último enemigo de la colección void removeLastEnemy(); // Elimina el último enemigo de la colección
auto isEmpty() const -> bool; // Comprueba si no hay enemigos [[nodiscard]] auto isEmpty() const -> bool; // Comprueba si no hay enemigos
// Actualización y renderizado // Actualización y renderizado
void update(float delta_time); // Actualiza todos los enemigos void update(float delta_time); // Actualiza todos los enemigos

View File

@@ -32,9 +32,9 @@ class ItemManager {
// Prohibir copia y movimiento para evitar duplicación accidental // Prohibir copia y movimiento para evitar duplicación accidental
ItemManager(const ItemManager&) = delete; ItemManager(const ItemManager&) = delete;
ItemManager& operator=(const ItemManager&) = delete; auto operator=(const ItemManager&) -> ItemManager& = delete;
ItemManager(ItemManager&&) = delete; ItemManager(ItemManager&&) = delete;
ItemManager& operator=(ItemManager&&) = delete; auto operator=(ItemManager&&) -> ItemManager& = delete;
// Gestión de items // Gestión de items
void addItem(std::shared_ptr<Item> item); // Añade un item a la colección void addItem(std::shared_ptr<Item> item); // Añade un item a la colección

View File

@@ -20,8 +20,8 @@ class ItemTracker {
private: private:
// Tipos anidados privados // Tipos anidados privados
struct Data { struct Data {
std::string name{}; // Nombre de la habitación donde se encuentra el objeto std::string name; // Nombre de la habitación donde se encuentra el objeto
std::vector<SDL_FPoint> pos{}; // Lista de objetos cogidos de la habitación std::vector<SDL_FPoint> pos; // Lista de objetos cogidos de la habitación
// Constructor para facilitar creación con posición inicial // Constructor para facilitar creación con posición inicial
Data(std::string name, const SDL_FPoint& position) Data(std::string name, const SDL_FPoint& position)

View File

@@ -166,15 +166,15 @@ auto Room::getRoom(Border border) -> std::string {
// Devuelve el tipo de tile que hay en ese pixel // Devuelve el tipo de tile que hay en ese pixel
auto Room::getTile(SDL_FPoint point) -> Tile { auto Room::getTile(SDL_FPoint point) -> Tile {
// Delega a CollisionMap y convierte el resultado // Delega a CollisionMap y convierte el resultado
const auto collision_tile = collision_map_->getTile(point); const auto COLLISION_TILE = collision_map_->getTile(point);
return static_cast<Tile>(collision_tile); return static_cast<Tile>(COLLISION_TILE);
} }
// Devuelve el tipo de tile en un índice del tilemap // Devuelve el tipo de tile en un índice del tilemap
auto Room::getTile(int index) -> Tile { auto Room::getTile(int index) -> Tile {
// Delega a CollisionMap y convierte el resultado // Delega a CollisionMap y convierte el resultado
const auto collision_tile = collision_map_->getTile(index); const auto COLLISION_TILE = collision_map_->getTile(index);
return static_cast<Tile>(collision_tile); return static_cast<Tile>(COLLISION_TILE);
} }
// Indica si hay colision con un enemigo a partir de un rectangulo // Indica si hay colision con un enemigo a partir de un rectangulo
@@ -190,8 +190,8 @@ auto Room::itemCollision(SDL_FRect& rect) -> bool {
// Obten la coordenada de la cuesta a partir de un punto perteneciente a ese tile // Obten la coordenada de la cuesta a partir de un punto perteneciente a ese tile
auto Room::getSlopeHeight(SDL_FPoint p, Tile slope) -> int { auto Room::getSlopeHeight(SDL_FPoint p, Tile slope) -> int {
// Delega a CollisionMap (método estático) // Delega a CollisionMap (método estático)
const auto collision_tile = static_cast<CollisionMap::Tile>(slope); const auto COLLISION_TILE = static_cast<CollisionMap::Tile>(slope);
return CollisionMap::getSlopeHeight(p, collision_tile); return CollisionMap::getSlopeHeight(p, COLLISION_TILE);
} }
// === Métodos de colisión (delegados a CollisionMap) === // === Métodos de colisión (delegados a CollisionMap) ===

View File

@@ -38,21 +38,21 @@ class Room {
}; };
struct Data { struct Data {
std::string number{}; // Numero de la habitación std::string number; // Numero de la habitación
std::string name{}; // Nombre de la habitación std::string name; // Nombre de la habitación
std::string bg_color{}; // Color de fondo de la habitación std::string bg_color; // Color de fondo de la habitación
std::string border_color{}; // Color del borde de la pantalla std::string border_color; // Color del borde de la pantalla
std::string item_color1{}; // Color 1 para los items de la habitación std::string item_color1; // Color 1 para los items de la habitación
std::string item_color2{}; // Color 2 para los items de la habitación std::string item_color2; // Color 2 para los items de la habitación
std::string upper_room{}; // Identificador de la habitación que se encuentra arriba std::string upper_room; // Identificador de la habitación que se encuentra arriba
std::string lower_room{}; // Identificador de la habitación que se encuentra abajo std::string lower_room; // Identificador de la habitación que se encuentra abajo
std::string left_room{}; // Identificador de la habitación que se encuentra a la izquierda std::string left_room; // Identificador de la habitación que se encuentra a la izquierda
std::string right_room{}; // Identificador de la habitación que se encuentra a la derecha std::string right_room; // Identificador de la habitación que se encuentra a la derecha
std::string tile_set_file{}; // Imagen con los gráficos para la habitación std::string tile_set_file; // Imagen con los gráficos para la habitación
int conveyor_belt_direction{0}; // Sentido en el que arrastran las superficies automáticas de la habitación int conveyor_belt_direction{0}; // Sentido en el que arrastran las superficies automáticas de la habitación
std::vector<int> tile_map{}; // Índice de los tiles a dibujar en la habitación (embebido desde YAML) std::vector<int> tile_map; // Índice de los tiles a dibujar en la habitación (embebido desde YAML)
std::vector<Enemy::Data> enemies{}; // Listado con los enemigos de la habitación std::vector<Enemy::Data> enemies; // Listado con los enemigos de la habitación
std::vector<Item::Data> items{}; // Listado con los items que hay en la habitación std::vector<Item::Data> items; // Listado con los items que hay en la habitación
}; };
// Constructor y destructor // Constructor y destructor
@@ -88,7 +88,7 @@ class Room {
auto checkLeftSlopes(const SDL_FPoint& p) -> bool; // Comprueba las colisiones auto checkLeftSlopes(const SDL_FPoint& p) -> bool; // Comprueba las colisiones
auto checkRightSlopes(const LineVertical& line) -> int; // Comprueba las colisiones auto checkRightSlopes(const LineVertical& line) -> int; // Comprueba las colisiones
auto checkRightSlopes(const SDL_FPoint& p) -> bool; // Comprueba las colisiones auto checkRightSlopes(const SDL_FPoint& p) -> bool; // Comprueba las colisiones
auto getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal*; // Obtiene puntero a slope en un punto [[nodiscard]] auto getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal*; // Obtiene puntero a slope en un punto
void setPaused(bool value); // Pone el mapa en modo pausa void setPaused(bool value); // Pone el mapa en modo pausa
[[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; } // Obten la direccion de las superficies automaticas [[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; } // Obten la direccion de las superficies automaticas

View File

@@ -26,9 +26,13 @@ auto RoomLoader::convertAutoSurface(const fkyaml::node& node) -> int {
return node.get_value<int>(); return node.get_value<int>();
} }
if (node.is_string()) { if (node.is_string()) {
const std::string value = node.get_value<std::string>(); const auto VALUE = node.get_value<std::string>();
if (value == "left") return -1; if (VALUE == "left") {
if (value == "right") return 1; return -1;
}
if (VALUE == "right") {
return 1;
}
} }
return 0; // "none" o default return 0; // "none" o default
} }

View File

@@ -276,7 +276,7 @@ void init() {
// Establece la ruta del fichero de configuración // Establece la ruta del fichero de configuración
void setConfigFile(const std::string& path) { void setConfigFile(const std::string& path) {
config_file_path_ = path; config_file_path = path;
} }
// Carga las opciones desde el fichero configurado // Carga las opciones desde el fichero configurado
@@ -286,10 +286,10 @@ auto loadFromFile() -> bool {
version = ""; version = "";
// Intenta abrir y leer el fichero // Intenta abrir y leer el fichero
std::ifstream file(config_file_path_); std::ifstream file(config_file_path);
if (!file.good()) { if (!file.good()) {
if (console) { if (console) {
std::cout << "Config file not found, creating default: " << config_file_path_ << '\n'; std::cout << "Config file not found, creating default: " << config_file_path << '\n';
} }
saveToFile(); saveToFile();
return true; return true;
@@ -301,7 +301,7 @@ auto loadFromFile() -> bool {
try { try {
if (console) { if (console) {
std::cout << "Reading config file: " << config_file_path_ << '\n'; std::cout << "Reading config file: " << config_file_path << '\n';
} }
// Parsea el YAML // Parsea el YAML
@@ -351,7 +351,7 @@ auto loadFromFile() -> bool {
// filter (ahora es string) // filter (ahora es string)
if (vid.contains("filter")) { if (vid.contains("filter")) {
try { try {
std::string filter_str = vid["filter"].get_value<std::string>(); auto filter_str = vid["filter"].get_value<std::string>();
video.filter = stringToFilter(filter_str); video.filter = stringToFilter(filter_str);
} catch (...) { } catch (...) {
video.filter = GameDefaults::VIDEO_FILTER; video.filter = GameDefaults::VIDEO_FILTER;
@@ -392,7 +392,7 @@ auto loadFromFile() -> bool {
if (vid.contains("palette")) { if (vid.contains("palette")) {
try { try {
std::string palette_str = vid["palette"].get_value<std::string>(); auto palette_str = vid["palette"].get_value<std::string>();
if (isValidPalette(palette_str)) { if (isValidPalette(palette_str)) {
video.palette = palette_str; video.palette = palette_str;
} else { } else {
@@ -417,7 +417,7 @@ auto loadFromFile() -> bool {
if (border.contains("width")) { if (border.contains("width")) {
try { try {
float val = border["width"].get_value<float>(); auto val = border["width"].get_value<float>();
video.border.width = (val > 0) ? val : GameDefaults::BORDER_WIDTH; video.border.width = (val > 0) ? val : GameDefaults::BORDER_WIDTH;
} catch (...) { } catch (...) {
video.border.width = GameDefaults::BORDER_WIDTH; video.border.width = GameDefaults::BORDER_WIDTH;
@@ -426,7 +426,7 @@ auto loadFromFile() -> bool {
if (border.contains("height")) { if (border.contains("height")) {
try { try {
float val = border["height"].get_value<float>(); auto val = border["height"].get_value<float>();
video.border.height = (val > 0) ? val : GameDefaults::BORDER_HEIGHT; video.border.height = (val > 0) ? val : GameDefaults::BORDER_HEIGHT;
} catch (...) { } catch (...) {
video.border.height = GameDefaults::BORDER_HEIGHT; video.border.height = GameDefaults::BORDER_HEIGHT;
@@ -441,7 +441,7 @@ auto loadFromFile() -> bool {
if (ctrl.contains("key_left")) { if (ctrl.contains("key_left")) {
try { try {
std::string key_str = ctrl["key_left"].get_value<std::string>(); auto key_str = ctrl["key_left"].get_value<std::string>();
keyboard_controls.key_left = stringToScancode(key_str, GameDefaults::CONTROL_KEY_LEFT); keyboard_controls.key_left = stringToScancode(key_str, GameDefaults::CONTROL_KEY_LEFT);
} catch (...) { } catch (...) {
keyboard_controls.key_left = GameDefaults::CONTROL_KEY_LEFT; keyboard_controls.key_left = GameDefaults::CONTROL_KEY_LEFT;
@@ -450,7 +450,7 @@ auto loadFromFile() -> bool {
if (ctrl.contains("key_right")) { if (ctrl.contains("key_right")) {
try { try {
std::string key_str = ctrl["key_right"].get_value<std::string>(); auto key_str = ctrl["key_right"].get_value<std::string>();
keyboard_controls.key_right = stringToScancode(key_str, GameDefaults::CONTROL_KEY_RIGHT); keyboard_controls.key_right = stringToScancode(key_str, GameDefaults::CONTROL_KEY_RIGHT);
} catch (...) { } catch (...) {
keyboard_controls.key_right = GameDefaults::CONTROL_KEY_RIGHT; keyboard_controls.key_right = GameDefaults::CONTROL_KEY_RIGHT;
@@ -459,7 +459,7 @@ auto loadFromFile() -> bool {
if (ctrl.contains("key_jump")) { if (ctrl.contains("key_jump")) {
try { try {
std::string key_str = ctrl["key_jump"].get_value<std::string>(); auto key_str = ctrl["key_jump"].get_value<std::string>();
keyboard_controls.key_jump = stringToScancode(key_str, GameDefaults::CONTROL_KEY_JUMP); keyboard_controls.key_jump = stringToScancode(key_str, GameDefaults::CONTROL_KEY_JUMP);
} catch (...) { } catch (...) {
keyboard_controls.key_jump = GameDefaults::CONTROL_KEY_JUMP; keyboard_controls.key_jump = GameDefaults::CONTROL_KEY_JUMP;
@@ -473,7 +473,7 @@ auto loadFromFile() -> bool {
if (gp.contains("button_left")) { if (gp.contains("button_left")) {
try { try {
std::string button_str = gp["button_left"].get_value<std::string>(); auto button_str = gp["button_left"].get_value<std::string>();
gamepad_controls.button_left = stringToGamepadButton(button_str, GameDefaults::GAMEPAD_BUTTON_LEFT); gamepad_controls.button_left = stringToGamepadButton(button_str, GameDefaults::GAMEPAD_BUTTON_LEFT);
} catch (...) { } catch (...) {
gamepad_controls.button_left = GameDefaults::GAMEPAD_BUTTON_LEFT; gamepad_controls.button_left = GameDefaults::GAMEPAD_BUTTON_LEFT;
@@ -482,7 +482,7 @@ auto loadFromFile() -> bool {
if (gp.contains("button_right")) { if (gp.contains("button_right")) {
try { try {
std::string button_str = gp["button_right"].get_value<std::string>(); auto button_str = gp["button_right"].get_value<std::string>();
gamepad_controls.button_right = stringToGamepadButton(button_str, GameDefaults::GAMEPAD_BUTTON_RIGHT); gamepad_controls.button_right = stringToGamepadButton(button_str, GameDefaults::GAMEPAD_BUTTON_RIGHT);
} catch (...) { } catch (...) {
gamepad_controls.button_right = GameDefaults::GAMEPAD_BUTTON_RIGHT; gamepad_controls.button_right = GameDefaults::GAMEPAD_BUTTON_RIGHT;
@@ -491,7 +491,7 @@ auto loadFromFile() -> bool {
if (gp.contains("button_jump")) { if (gp.contains("button_jump")) {
try { try {
std::string button_str = gp["button_jump"].get_value<std::string>(); auto button_str = gp["button_jump"].get_value<std::string>();
gamepad_controls.button_jump = stringToGamepadButton(button_str, GameDefaults::GAMEPAD_BUTTON_JUMP); gamepad_controls.button_jump = stringToGamepadButton(button_str, GameDefaults::GAMEPAD_BUTTON_JUMP);
} catch (...) { } catch (...) {
gamepad_controls.button_jump = GameDefaults::GAMEPAD_BUTTON_JUMP; gamepad_controls.button_jump = GameDefaults::GAMEPAD_BUTTON_JUMP;
@@ -519,16 +519,16 @@ auto loadFromFile() -> bool {
// Guarda las opciones al fichero configurado // Guarda las opciones al fichero configurado
auto saveToFile() -> bool { auto saveToFile() -> bool {
// Abre el fichero para escritura // Abre el fichero para escritura
std::ofstream file(config_file_path_); std::ofstream file(config_file_path);
if (!file.is_open()) { if (!file.is_open()) {
if (console) { if (console) {
std::cerr << "Error: Unable to open file " << config_file_path_ << " for writing\n"; std::cerr << "Error: Unable to open file " << config_file_path << " for writing\n";
} }
return false; return false;
} }
if (console) { if (console) {
std::cout << "Writing config file: " << config_file_path_ << '\n'; std::cout << "Writing config file: " << config_file_path << '\n';
} }
// Escribe el fichero manualmente para controlar el orden y los comentarios // Escribe el fichero manualmente para controlar el orden y los comentarios

View File

@@ -85,7 +85,7 @@ struct Video {
bool keep_aspect{GameDefaults::VIDEO_KEEP_ASPECT}; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa bool keep_aspect{GameDefaults::VIDEO_KEEP_ASPECT}; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa
Border border{}; // Borde de la pantalla Border border{}; // Borde de la pantalla
std::string palette{GameDefaults::PALETTE_NAME}; // Paleta de colores a usar en el juego std::string palette{GameDefaults::PALETTE_NAME}; // Paleta de colores a usar en el juego
std::string info{}; // Información sobre el modo de vídeo std::string info; // Información sobre el modo de vídeo
}; };
// Estructura para las opciones de musica // Estructura para las opciones de musica
@@ -127,7 +127,7 @@ inline KeyboardControls keyboard_controls{}; // Teclas usadas para jugar
inline GamepadControls gamepad_controls{}; // Botones del gamepad usados para jugar inline GamepadControls gamepad_controls{}; // Botones del gamepad usados para jugar
// Ruta completa del fichero de configuración (establecida mediante setConfigFile) // Ruta completa del fichero de configuración (establecida mediante setConfigFile)
inline std::string config_file_path_{}; inline std::string config_file_path{};
// --- Funciones --- // --- Funciones ---
void init(); // Crea e inicializa las opciones del programa void init(); // Crea e inicializa las opciones del programa

View File

@@ -23,7 +23,7 @@
// Constructor // Constructor
Ending2::Ending2() Ending2::Ending2()
: delta_timer_(std::make_unique<DeltaTimer>()), : delta_timer_(std::make_unique<DeltaTimer>()),
state_{EndingState::PRE_CREDITS, STATE_PRE_CREDITS_DURATION} { state_{.state = EndingState::PRE_CREDITS, .duration = STATE_PRE_CREDITS_DURATION} {
// Establece la escena // Establece la escena
SceneManager::current = SceneManager::Scene::ENDING2; SceneManager::current = SceneManager::Scene::ENDING2;
SceneManager::options = SceneManager::Options::NONE; SceneManager::options = SceneManager::Options::NONE;

View File

@@ -576,7 +576,7 @@ void Game::checkEndGameCheevos() {
// Inicializa al jugador // Inicializa al jugador
void Game::initPlayer(const Player::SpawnData& spawn_point, std::shared_ptr<Room> room) { void Game::initPlayer(const Player::SpawnData& spawn_point, std::shared_ptr<Room> room) {
std::string player_animations = Options::cheats.alternate_skin == Options::Cheat::State::ENABLED ? "player2.yaml" : "player.yaml"; std::string player_animations = Options::cheats.alternate_skin == Options::Cheat::State::ENABLED ? "player2.yaml" : "player.yaml";
const Player::Data PLAYER{spawn_point, player_animations, std::move(room)}; const Player::Data PLAYER{.spawn_data = spawn_point, .animations_path = player_animations, .room = std::move(room)};
player_ = std::make_shared<Player>(PLAYER); player_ = std::make_shared<Player>(PLAYER);
} }

View File

@@ -41,7 +41,7 @@ class Game {
struct DemoData { struct DemoData {
float time_accumulator{0.0F}; // Acumulador de tiempo para el modo demo float time_accumulator{0.0F}; // Acumulador de tiempo para el modo demo
int room_index{0}; // Índice para el vector de habitaciones int room_index{0}; // Índice para el vector de habitaciones
std::vector<std::string> rooms{}; // Listado con los mapas de la demo std::vector<std::string> rooms; // Listado con los mapas de la demo
}; };
// --- Métodos --- // --- Métodos ---

View File

@@ -76,20 +76,20 @@ void Logo::updateJAILGAMES(float delta_time) {
} }
// Calcular el progreso de la animación (0.0 a 1.0) // Calcular el progreso de la animación (0.0 a 1.0)
const float progress = std::clamp(state_time_ / JAILGAMES_SLIDE_DURATION, 0.0F, 1.0F); const float PROGRESS = std::clamp(state_time_ / JAILGAMES_SLIDE_DURATION, 0.0F, 1.0F);
// Aplicar función de suavizado seleccionada aleatoriamente (permite overshoot para efecto de rebote) // Aplicar función de suavizado seleccionada aleatoriamente (permite overshoot para efecto de rebote)
// La posición final exacta se garantiza en updateState() antes de transicionar // La posición final exacta se garantiza en updateState() antes de transicionar
const float eased_progress = easing_function_(progress); const float EASED_PROGRESS = easing_function_(PROGRESS);
// Actualizar cada línea del sprite JAILGAMES interpolando con easing // Actualizar cada línea del sprite JAILGAMES interpolando con easing
for (size_t i = 0; i < jailgames_sprite_.size(); ++i) { for (size_t i = 0; i < jailgames_sprite_.size(); ++i) {
// Interpolar entre posición inicial y destino usando el progreso suavizado // Interpolar entre posición inicial y destino usando el progreso suavizado
const float initial_x = static_cast<float>(jailgames_initial_x_[i]); const auto INITIAL_X = static_cast<float>(jailgames_initial_x_[i]);
const float dest_x = static_cast<float>(JAILGAMES_DEST_X); const auto DEST_X = static_cast<float>(JAILGAMES_DEST_X);
const float new_x = initial_x + (dest_x - initial_x) * eased_progress; const float NEW_X = INITIAL_X + ((DEST_X - INITIAL_X) * EASED_PROGRESS);
jailgames_sprite_[i]->setX(new_x); jailgames_sprite_[i]->setX(NEW_X);
} }
} }
@@ -275,10 +275,10 @@ void Logo::initSprites() {
// Calcular posición inicial (alternando entre derecha e izquierda) // Calcular posición inicial (alternando entre derecha e izquierda)
constexpr int LINE_OFFSET = 6; constexpr int LINE_OFFSET = 6;
const int initial_x = (i % 2 == 0) ? (256 + (i * LINE_OFFSET)) : (static_cast<int>(-WIDTH) - (i * LINE_OFFSET)); const int INITIAL_X = (i % 2 == 0) ? (256 + (i * LINE_OFFSET)) : (static_cast<int>(-WIDTH) - (i * LINE_OFFSET));
jailgames_initial_x_.push_back(initial_x); jailgames_initial_x_.push_back(INITIAL_X);
jailgames_sprite_.at(i)->setX(initial_x); jailgames_sprite_.at(i)->setX(INITIAL_X);
jailgames_sprite_.at(i)->setY(83 + i); jailgames_sprite_.at(i)->setY(83 + i);
} }
} }

View File

@@ -90,7 +90,7 @@ void Notifier::update(float delta_time) {
if (notification.rect.y >= notification.y) { if (notification.rect.y >= notification.y) {
notification.rect.y = notification.y; notification.rect.y = notification.y;
notification.state = Status::STAY; notification.state = Status::STAY;
notification.elapsed_time = 0.0f; notification.elapsed_time = 0.0F;
} }
break; break;
} }
@@ -163,7 +163,7 @@ void Notifier::show(std::vector<std::string> texts, const Style& style, int icon
const auto PADDING_IN_H = TEXT_SIZE; const auto PADDING_IN_H = TEXT_SIZE;
const auto PADDING_IN_V = TEXT_SIZE / 2; const auto PADDING_IN_V = TEXT_SIZE / 2;
const int ICON_SPACE = icon >= 0 ? ICON_SIZE + PADDING_IN_H : 0; const int ICON_SPACE = icon >= 0 ? ICON_SIZE + PADDING_IN_H : 0;
const TextAlign text_is = ICON_SPACE > 0 ? TextAlign::LEFT : style.text_align; const TextAlign TEXT_IS = ICON_SPACE > 0 ? TextAlign::LEFT : style.text_align;
const float WIDTH = Options::game.width - (PADDING_OUT * 2); const float WIDTH = Options::game.width - (PADDING_OUT * 2);
const float HEIGHT = (TEXT_SIZE * texts.size()) + (PADDING_IN_V * 2); const float HEIGHT = (TEXT_SIZE * texts.size()) + (PADDING_IN_V * 2);
const auto SHAPE = style.shape; const auto SHAPE = style.shape;
@@ -235,7 +235,7 @@ void Notifier::show(std::vector<std::string> texts, const Style& style, int icon
const auto COLOR = style.text_color; const auto COLOR = style.text_color;
int iterator = 0; int iterator = 0;
for (const auto& text : texts) { for (const auto& text : texts) {
switch (text_is) { switch (TEXT_IS) {
case TextAlign::LEFT: case TextAlign::LEFT:
text_->writeColored(PADDING_IN_H + ICON_SPACE, PADDING_IN_V + (iterator * (TEXT_SIZE + 1)), text, COLOR); text_->writeColored(PADDING_IN_H + ICON_SPACE, PADDING_IN_V + (iterator * (TEXT_SIZE + 1)), text, COLOR);
break; break;

View File

@@ -71,17 +71,17 @@ class Notifier {
struct Notification { struct Notification {
std::shared_ptr<Surface> surface{nullptr}; std::shared_ptr<Surface> surface{nullptr};
std::shared_ptr<SurfaceSprite> sprite{nullptr}; std::shared_ptr<SurfaceSprite> sprite{nullptr};
std::vector<std::string> texts{}; std::vector<std::string> texts;
Status state{Status::RISING}; Status state{Status::RISING};
Shape shape{Shape::SQUARED}; Shape shape{Shape::SQUARED};
SDL_FRect rect{0.0F, 0.0F, 0.0F, 0.0F}; SDL_FRect rect{0.0F, 0.0F, 0.0F, 0.0F};
int y{0}; int y{0};
int travel_dist{0}; int travel_dist{0};
std::string code{}; std::string code;
bool can_be_removed{true}; bool can_be_removed{true};
int height{0}; int height{0};
float elapsed_time{0.0f}; float elapsed_time{0.0F};
float display_duration{0.0f}; float display_duration{0.0F};
}; };
// Constantes // Constantes

View File

@@ -11,10 +11,10 @@
* - InOut: Aceleración + Desaceleración (slow -> fast -> slow) * - InOut: Aceleración + Desaceleración (slow -> fast -> slow)
*/ */
#ifndef EASING_FUNCTIONS_HPP #pragma once
#define EASING_FUNCTIONS_HPP
#include <cmath> #include <cmath>
#include <numbers>
#ifndef M_PI #ifndef M_PI
#define M_PI 3.14159265358979323846 #define M_PI 3.14159265358979323846
@@ -22,252 +22,230 @@
namespace Easing { namespace Easing {
// ============================================================================
// LINEAR // LINEAR
// ============================================================================ inline auto linear(float t) -> float {
inline float linear(float t) {
return t; return t;
} }
// ============================================================================
// QUAD (Cuadrática: t^2) // QUAD (Cuadrática: t^2)
// ============================================================================ inline auto quadIn(float t) -> float {
inline float quadIn(float t) {
return t * t; return t * t;
} }
inline float quadOut(float t) { inline auto quadOut(float t) -> float {
return t * (2.0F - t); return t * (2.0F - t);
} }
inline float quadInOut(float t) { inline auto quadInOut(float t) -> float {
if (t < 0.5F) { if (t < 0.5F) {
return 2.0F * t * t; return 2.0F * t * t;
} }
return -1.0F + (4.0F - 2.0F * t) * t; return -1.0F + ((4.0F - 2.0F * t) * t);
} }
// ============================================================================
// CUBIC (Cúbica: t^3) // CUBIC (Cúbica: t^3)
// ============================================================================ inline auto cubicIn(float t) -> float {
inline float cubicIn(float t) {
return t * t * t; return t * t * t;
} }
inline float cubicOut(float t) { inline auto cubicOut(float t) -> float {
const float f = t - 1.0F; const float F = t - 1.0F;
return f * f * f + 1.0F; return (F * F * F) + 1.0F;
} }
inline float cubicInOut(float t) { inline auto cubicInOut(float t) -> float {
if (t < 0.5F) { if (t < 0.5F) {
return 4.0F * t * t * t; return 4.0F * t * t * t;
} }
const float f = (2.0F * t - 2.0F); const float F = ((2.0F * t) - 2.0F);
return 0.5F * f * f * f + 1.0F; return (0.5F * F * F * F) + 1.0F;
} }
// ============================================================================
// QUART (Cuártica: t^4) // QUART (Cuártica: t^4)
// ============================================================================ inline auto quartIn(float t) -> float {
inline float quartIn(float t) {
return t * t * t * t; return t * t * t * t;
} }
inline float quartOut(float t) { inline auto quartOut(float t) -> float {
const float f = t - 1.0F; const float F = t - 1.0F;
return 1.0F - f * f * f * f; return 1.0F - (F * F * F * F);
} }
inline float quartInOut(float t) { inline auto quartInOut(float t) -> float {
if (t < 0.5F) { if (t < 0.5F) {
return 8.0F * t * t * t * t; return 8.0F * t * t * t * t;
} }
const float f = t - 1.0F; const float F = t - 1.0F;
return 1.0F - 8.0F * f * f * f * f; return 1.0F - (8.0F * F * F * F * F);
} }
// ============================================================================
// QUINT (Quíntica: t^5) // QUINT (Quíntica: t^5)
// ============================================================================ inline auto quintIn(float t) -> float {
inline float quintIn(float t) {
return t * t * t * t * t; return t * t * t * t * t;
} }
inline float quintOut(float t) { inline auto quintOut(float t) -> float {
const float f = t - 1.0F; const float F = t - 1.0F;
return f * f * f * f * f + 1.0F; return (F * F * F * F * F) + 1.0F;
} }
inline float quintInOut(float t) { inline auto quintInOut(float t) -> float {
if (t < 0.5F) { if (t < 0.5F) {
return 16.0F * t * t * t * t * t; return 16.0F * t * t * t * t * t;
} }
const float f = (2.0F * t - 2.0F); const float F = ((2.0F * t) - 2.0F);
return 0.5F * f * f * f * f * f + 1.0F; return (0.5F * F * F * F * F * F) + 1.0F;
} }
// ============================================================================
// SINE (Sinusoidal) // SINE (Sinusoidal)
// ============================================================================ inline auto sineIn(float t) -> float {
return 1.0F - std::cos(t * std::numbers::pi_v<float> * 0.5F);
inline float sineIn(float t) {
return 1.0F - std::cos(t * static_cast<float>(M_PI) * 0.5F);
} }
inline float sineOut(float t) { inline auto sineOut(float t) -> float {
return std::sin(t * static_cast<float>(M_PI) * 0.5F); return std::sin(t * std::numbers::pi_v<float> * 0.5F);
} }
inline float sineInOut(float t) { inline auto sineInOut(float t) -> float {
return 0.5F * (1.0F - std::cos(static_cast<float>(M_PI) * t)); return 0.5F * (1.0F - std::cos(std::numbers::pi_v<float> * t));
} }
// ============================================================================
// EXPO (Exponencial) // EXPO (Exponencial)
// ============================================================================ inline auto expoIn(float t) -> float {
if (t == 0.0F) {
inline float expoIn(float t) { return 0.0F;
if (t == 0.0F) return 0.0F; }
return std::pow(2.0F, 10.0F * (t - 1.0F)); return std::pow(2.0F, 10.0F * (t - 1.0F));
} }
inline float expoOut(float t) { inline auto expoOut(float t) -> float {
if (t == 1.0F) return 1.0F; if (t == 1.0F) {
return 1.0F;
}
return 1.0F - std::pow(2.0F, -10.0F * t); return 1.0F - std::pow(2.0F, -10.0F * t);
} }
inline float expoInOut(float t) { inline auto expoInOut(float t) -> float {
if (t == 0.0F || t == 1.0F) return t; if (t == 0.0F || t == 1.0F) {
return t;
}
if (t < 0.5F) { if (t < 0.5F) {
return 0.5F * std::pow(2.0F, (20.0F * t) - 10.0F); return 0.5F * std::pow(2.0F, (20.0F * t) - 10.0F);
} }
return 0.5F * (2.0F - std::pow(2.0F, -20.0F * t + 10.0F)); return 0.5F * (2.0F - std::pow(2.0F, (-20.0F * t) + 10.0F));
} }
// ============================================================================
// CIRC (Circular) // CIRC (Circular)
// ============================================================================ inline auto circIn(float t) -> float {
return 1.0F - std::sqrt(1.0F - (t * t));
inline float circIn(float t) {
return 1.0F - std::sqrt(1.0F - t * t);
} }
inline float circOut(float t) { inline auto circOut(float t) -> float {
const float f = t - 1.0F; const float F = t - 1.0F;
return std::sqrt(1.0F - f * f); return std::sqrt(1.0F - (F * F));
} }
inline float circInOut(float t) { inline auto circInOut(float t) -> float {
if (t < 0.5F) { if (t < 0.5F) {
return 0.5F * (1.0F - std::sqrt(1.0F - 4.0F * t * t)); return 0.5F * (1.0F - std::sqrt(1.0F - (4.0F * t * t)));
} }
const float f = 2.0F * t - 2.0F; const float F = (2.0F * t) - 2.0F;
return 0.5F * (std::sqrt(1.0F - f * f) + 1.0F); return 0.5F * (std::sqrt(1.0F - (F * F)) + 1.0F);
} }
// ============================================================================
// BACK (Overshoot - retrocede antes de avanzar) // BACK (Overshoot - retrocede antes de avanzar)
// ============================================================================ inline auto backIn(float t, float overshoot = 1.70158F) -> float {
inline float backIn(float t, float overshoot = 1.70158F) {
return t * t * ((overshoot + 1.0F) * t - overshoot); return t * t * ((overshoot + 1.0F) * t - overshoot);
} }
inline float backOut(float t, float overshoot = 1.70158F) { inline auto backOut(float t, float overshoot = 1.70158F) -> float {
const float f = t - 1.0F; const float F = t - 1.0F;
return f * f * ((overshoot + 1.0F) * f + overshoot) + 1.0F; return (F * F * ((overshoot + 1.0F) * F + overshoot)) + 1.0F;
} }
inline float backInOut(float t, float overshoot = 1.70158F) { inline auto backInOut(float t, float overshoot = 1.70158F) -> float {
const float s = overshoot * 1.525F; const float S = overshoot * 1.525F;
if (t < 0.5F) { if (t < 0.5F) {
const float f = 2.0F * t; const float F = 2.0F * t;
return 0.5F * (f * f * ((s + 1.0F) * f - s)); return 0.5F * (F * F * ((S + 1.0F) * F - S));
} }
const float f = 2.0F * t - 2.0F; const float F = (2.0F * t) - 2.0F;
return 0.5F * (f * f * ((s + 1.0F) * f + s) + 2.0F); return 0.5F * (F * F * ((S + 1.0F) * F + S) + 2.0F);
} }
// ============================================================================
// ELASTIC (Oscilación elástica - efecto de resorte) // ELASTIC (Oscilación elástica - efecto de resorte)
// ============================================================================ inline auto elasticIn(float t, float amplitude = 1.0F, float period = 0.3F) -> float {
if (t == 0.0F || t == 1.0F) {
return t;
}
inline float elasticIn(float t, float amplitude = 1.0F, float period = 0.3F) { const float S = period / (2.0F * std::numbers::pi_v<float>)*std::asin(1.0F / amplitude);
if (t == 0.0F || t == 1.0F) return t; const float F = t - 1.0F;
return -(amplitude * std::pow(2.0F, 10.0F * F) *
const float s = period / (2.0F * static_cast<float>(M_PI)) * std::asin(1.0F / amplitude); std::sin((F - S) * (2.0F * std::numbers::pi_v<float>) / period));
const float f = t - 1.0F;
return -(amplitude * std::pow(2.0F, 10.0F * f) *
std::sin((f - s) * (2.0F * static_cast<float>(M_PI)) / period));
} }
inline float elasticOut(float t, float amplitude = 1.0F, float period = 0.3F) { inline auto elasticOut(float t, float amplitude = 1.0F, float period = 0.3F) -> float {
if (t == 0.0F || t == 1.0F) return t; if (t == 0.0F || t == 1.0F) {
return t;
}
const float s = period / (2.0F * static_cast<float>(M_PI)) * std::asin(1.0F / amplitude); const float S = period / (2.0F * std::numbers::pi_v<float>)*std::asin(1.0F / amplitude);
return amplitude * std::pow(2.0F, -10.0F * t) * return (amplitude * std::pow(2.0F, -10.0F * t) *
std::sin((t - s) * (2.0F * static_cast<float>(M_PI)) / period) + 1.0F; std::sin((t - S) * (2.0F * std::numbers::pi_v<float>) / period)) +
1.0F;
} }
inline float elasticInOut(float t, float amplitude = 1.0F, float period = 0.3F) { inline auto elasticInOut(float t, float amplitude = 1.0F, float period = 0.3F) -> float {
if (t == 0.0F || t == 1.0F) return t; if (t == 0.0F || t == 1.0F) {
return t;
}
const float s = period / (2.0F * static_cast<float>(M_PI)) * std::asin(1.0F / amplitude); const float S = period / (2.0F * std::numbers::pi_v<float>)*std::asin(1.0F / amplitude);
if (t < 0.5F) { if (t < 0.5F) {
const float f = 2.0F * t - 1.0F; const float F = (2.0F * t) - 1.0F;
return -0.5F * (amplitude * std::pow(2.0F, 10.0F * f) * return -0.5F * (amplitude * std::pow(2.0F, 10.0F * F) * std::sin((F - S) * (2.0F * std::numbers::pi_v<float>) / period));
std::sin((f - s) * (2.0F * static_cast<float>(M_PI)) / period));
} }
const float f = 2.0F * t - 1.0F; const float F = (2.0F * t) - 1.0F;
return 0.5F * amplitude * std::pow(2.0F, -10.0F * f) * return (0.5F * amplitude * std::pow(2.0F, -10.0F * F) *
std::sin((f - s) * (2.0F * static_cast<float>(M_PI)) / period) + 1.0F; std::sin((F - S) * (2.0F * std::numbers::pi_v<float>) / period)) +
1.0F;
} }
// ============================================================================
// BOUNCE (Rebote - simula física de rebote) // BOUNCE (Rebote - simula física de rebote)
// ============================================================================ inline auto bounceOut(float t) -> float {
const float N1 = 7.5625F;
const float D1 = 2.75F;
inline float bounceOut(float t) { if (t < 1.0F / D1) {
const float n1 = 7.5625F; return N1 * t * t;
const float d1 = 2.75F;
if (t < 1.0F / d1) {
return n1 * t * t;
} }
if (t < 2.0F / d1) { if (t < 2.0F / D1) {
const float f = t - 1.5F / d1; const float F = t - (1.5F / D1);
return n1 * f * f + 0.75F; return (N1 * F * F) + 0.75F;
} }
if (t < 2.5F / d1) { if (t < 2.5F / D1) {
const float f = t - 2.25F / d1; const float F = t - (2.25F / D1);
return n1 * f * f + 0.9375F; return (N1 * F * F) + 0.9375F;
} }
const float f = t - 2.625F / d1; const float F = t - (2.625F / D1);
return n1 * f * f + 0.984375F; return (N1 * F * F) + 0.984375F;
} }
inline float bounceIn(float t) { inline auto bounceIn(float t) -> float {
return 1.0F - bounceOut(1.0F - t); return 1.0F - bounceOut(1.0F - t);
} }
inline float bounceInOut(float t) { inline auto bounceInOut(float t) -> float {
if (t < 0.5F) { if (t < 0.5F) {
return 0.5F * bounceIn(2.0F * t); return 0.5F * bounceIn(2.0F * t);
} }
return 0.5F * bounceOut(2.0F * t - 1.0F) + 0.5F; return (0.5F * bounceOut((2.0F * t) - 1.0F)) + 0.5F;
} }
} // namespace Easing } // namespace Easing
#endif // EASING_FUNCTIONS_HPP