arreglos varios pa que JailDoc puga tastar com va açò
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
#include <string.h> // Para strcpy, strlen
|
||||
|
||||
#define STB_VORBIS_HEADER_ONLY
|
||||
#include "external/stb_vorbis.h" // Para stb_vorbis_decode_memory
|
||||
#include "external/stb_vorbis.h" // Para stb_vorbis_open_memory i streaming
|
||||
|
||||
// --- Public Enums ---
|
||||
enum JA_Channel_state { JA_CHANNEL_INVALID,
|
||||
@@ -43,12 +43,16 @@ struct JA_Channel_t {
|
||||
|
||||
struct JA_Music_t {
|
||||
SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000};
|
||||
Uint32 length{0};
|
||||
Uint8* buffer{nullptr};
|
||||
|
||||
// OGG comprimit en memòria. Propietat nostra; es copia des del fitxer una
|
||||
// sola vegada en JA_LoadMusic i es descomprimix en chunks per streaming.
|
||||
Uint8* ogg_data{nullptr};
|
||||
Uint32 ogg_length{0};
|
||||
stb_vorbis* vorbis{nullptr}; // Handle del decoder, viu tot el cicle del JA_Music_t
|
||||
|
||||
char* filename{nullptr};
|
||||
|
||||
int pos{0};
|
||||
int times{0};
|
||||
int times{0}; // Loops restants (-1 = infinit, 0 = un sol play)
|
||||
SDL_AudioStream* stream{nullptr};
|
||||
JA_Music_state state{JA_MUSIC_INVALID};
|
||||
};
|
||||
@@ -88,6 +92,73 @@ 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 void JA_CrossfadeMusic(JA_Music_t* music, int crossfade_ms, int loop = -1);
|
||||
|
||||
// --- Music streaming internals ---
|
||||
// Bytes-per-sample per canal (sempre s16)
|
||||
static constexpr int JA_MUSIC_BYTES_PER_SAMPLE = 2;
|
||||
// Quants shorts decodifiquem per crida a get_samples_short_interleaved.
|
||||
// 8192 shorts = 4096 samples/channel en estèreo ≈ 85ms de so a 48kHz.
|
||||
static constexpr int JA_MUSIC_CHUNK_SHORTS = 8192;
|
||||
// Umbral d'audio per davant del cursor de reproducció. Mantenim ≥ 0.5 s a
|
||||
// l'SDL_AudioStream per absorbir jitter de frame i evitar underruns.
|
||||
static constexpr float JA_MUSIC_LOW_WATER_SECONDS = 0.5f;
|
||||
|
||||
// Decodifica un chunk del vorbis i el volca a l'stream. Retorna samples
|
||||
// decodificats per canal (0 = EOF de l'stream vorbis).
|
||||
inline int JA_FeedMusicChunk(JA_Music_t* music) {
|
||||
if (!music || !music->vorbis || !music->stream) return 0;
|
||||
|
||||
short chunk[JA_MUSIC_CHUNK_SHORTS];
|
||||
const int channels = music->spec.channels;
|
||||
const int samples_per_channel = stb_vorbis_get_samples_short_interleaved(
|
||||
music->vorbis,
|
||||
channels,
|
||||
chunk,
|
||||
JA_MUSIC_CHUNK_SHORTS);
|
||||
if (samples_per_channel <= 0) return 0;
|
||||
|
||||
const int bytes = samples_per_channel * channels * JA_MUSIC_BYTES_PER_SAMPLE;
|
||||
SDL_PutAudioStreamData(music->stream, chunk, bytes);
|
||||
return samples_per_channel;
|
||||
}
|
||||
|
||||
// Reompli l'stream fins que tinga ≥ JA_MUSIC_LOW_WATER_SECONDS bufferats.
|
||||
// En arribar a EOF del vorbis, aplica el loop (times) o deixa drenar.
|
||||
inline void JA_PumpMusic(JA_Music_t* music) {
|
||||
if (!music || !music->vorbis || !music->stream) return;
|
||||
|
||||
const int bytes_per_second = music->spec.freq * music->spec.channels * JA_MUSIC_BYTES_PER_SAMPLE;
|
||||
const int low_water_bytes = static_cast<int>(JA_MUSIC_LOW_WATER_SECONDS * static_cast<float>(bytes_per_second));
|
||||
|
||||
while (SDL_GetAudioStreamAvailable(music->stream) < low_water_bytes) {
|
||||
const int decoded = JA_FeedMusicChunk(music);
|
||||
if (decoded > 0) continue;
|
||||
|
||||
// EOF: si queden loops, rebobinar; si no, tallar i deixar drenar.
|
||||
if (music->times != 0) {
|
||||
stb_vorbis_seek_start(music->vorbis);
|
||||
if (music->times > 0) music->times--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pre-carrega `duration_ms` de so dins l'stream actual abans que l'stream
|
||||
// siga robat per outgoing_music (crossfade o fade-out). Imprescindible amb
|
||||
// streaming: l'stream robat no es pot re-alimentar perquè perd la referència
|
||||
// al seu vorbis decoder. No aplica loop — si el vorbis s'esgota abans, parem.
|
||||
inline void JA_PreFillOutgoing(JA_Music_t* music, int duration_ms) {
|
||||
if (!music || !music->vorbis || !music->stream) return;
|
||||
|
||||
const int bytes_per_second = music->spec.freq * music->spec.channels * JA_MUSIC_BYTES_PER_SAMPLE;
|
||||
const int needed_bytes = static_cast<int>((static_cast<int64_t>(duration_ms) * bytes_per_second) / 1000);
|
||||
|
||||
while (SDL_GetAudioStreamAvailable(music->stream) < needed_bytes) {
|
||||
const int decoded = JA_FeedMusicChunk(music);
|
||||
if (decoded <= 0) break; // EOF: deixem drenar el que hi haja
|
||||
}
|
||||
}
|
||||
|
||||
// --- Core Functions ---
|
||||
|
||||
inline void JA_Update() {
|
||||
@@ -120,14 +191,11 @@ inline void JA_Update() {
|
||||
}
|
||||
}
|
||||
|
||||
// Buffering de musica en loop
|
||||
if (current_music->times != 0) {
|
||||
if ((Uint32)SDL_GetAudioStreamAvailable(current_music->stream) < (current_music->length / 2)) {
|
||||
SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length);
|
||||
}
|
||||
if (current_music->times > 0) current_music->times--;
|
||||
} else {
|
||||
if (SDL_GetAudioStreamAvailable(current_music->stream) == 0) JA_StopMusic();
|
||||
// Streaming: rellenem l'stream fins al low-water-mark i parem si el
|
||||
// vorbis s'ha esgotat i no queden loops.
|
||||
JA_PumpMusic(current_music);
|
||||
if (current_music->times == 0 && SDL_GetAudioStreamAvailable(current_music->stream) == 0) {
|
||||
JA_StopMusic();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,19 +240,31 @@ inline void JA_Quit() {
|
||||
// --- Music Functions ---
|
||||
|
||||
inline JA_Music_t* JA_LoadMusic(const Uint8* buffer, Uint32 length) {
|
||||
JA_Music_t* music = new JA_Music_t();
|
||||
if (!buffer || length == 0) return nullptr;
|
||||
|
||||
int chan, samplerate;
|
||||
short* output;
|
||||
music->length = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &output) * chan * 2;
|
||||
// Còpia del OGG comprimit: stb_vorbis llig de forma persistent aquesta
|
||||
// memòria mentre el handle estiga viu, així que hem de posseir-la nosaltres.
|
||||
Uint8* ogg_copy = static_cast<Uint8*>(SDL_malloc(length));
|
||||
if (!ogg_copy) return nullptr;
|
||||
SDL_memcpy(ogg_copy, buffer, length);
|
||||
|
||||
music->spec.channels = chan;
|
||||
music->spec.freq = samplerate;
|
||||
int error = 0;
|
||||
stb_vorbis* vorbis = stb_vorbis_open_memory(ogg_copy, static_cast<int>(length), &error, nullptr);
|
||||
if (!vorbis) {
|
||||
SDL_free(ogg_copy);
|
||||
SDL_Log("JA_LoadMusic: stb_vorbis_open_memory failed (error %d)", error);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* music = new JA_Music_t();
|
||||
music->ogg_data = ogg_copy;
|
||||
music->ogg_length = length;
|
||||
music->vorbis = vorbis;
|
||||
|
||||
const stb_vorbis_info info = stb_vorbis_get_info(vorbis);
|
||||
music->spec.channels = info.channels;
|
||||
music->spec.freq = static_cast<int>(info.sample_rate);
|
||||
music->spec.format = SDL_AUDIO_S16;
|
||||
music->buffer = static_cast<Uint8*>(SDL_malloc(music->length));
|
||||
SDL_memcpy(music->buffer, output, music->length);
|
||||
free(output);
|
||||
music->pos = 0;
|
||||
music->state = JA_MUSIC_STOPPED;
|
||||
|
||||
return music;
|
||||
@@ -223,23 +303,29 @@ inline JA_Music_t* JA_LoadMusic(const char* filename) {
|
||||
}
|
||||
|
||||
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 || !music->vorbis) return;
|
||||
|
||||
JA_StopMusic();
|
||||
|
||||
current_music = music;
|
||||
current_music->pos = 0;
|
||||
current_music->state = JA_MUSIC_PLAYING;
|
||||
current_music->times = loop;
|
||||
|
||||
// Rebobinem l'stream de vorbis al principi. Cobreix tant play-per-primera-
|
||||
// vegada com replays/canvis de track que tornen a la mateixa pista.
|
||||
stb_vorbis_seek_start(current_music->vorbis);
|
||||
|
||||
current_music->stream = SDL_CreateAudioStream(¤t_music->spec, &JA_audioSpec);
|
||||
if (!current_music->stream) { // Comprobar creación de stream
|
||||
if (!current_music->stream) {
|
||||
SDL_Log("Failed to create audio stream!");
|
||||
current_music->state = JA_MUSIC_STOPPED;
|
||||
return;
|
||||
}
|
||||
if (!SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length)) printf("[ERROR] SDL_PutAudioStreamData failed!\n");
|
||||
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
|
||||
|
||||
// Pre-cargem el buffer abans de bindejar per evitar un underrun inicial.
|
||||
JA_PumpMusic(current_music);
|
||||
|
||||
if (!SDL_BindAudioStream(sdlAudioDevice, current_music->stream)) printf("[ERROR] SDL_BindAudioStream failed!\n");
|
||||
}
|
||||
|
||||
@@ -276,12 +362,16 @@ inline void JA_StopMusic() {
|
||||
|
||||
if (!current_music || current_music->state == JA_MUSIC_INVALID || current_music->state == JA_MUSIC_STOPPED) return;
|
||||
|
||||
current_music->pos = 0;
|
||||
current_music->state = JA_MUSIC_STOPPED;
|
||||
if (current_music->stream) {
|
||||
SDL_DestroyAudioStream(current_music->stream);
|
||||
current_music->stream = nullptr;
|
||||
}
|
||||
// Deixem el handle de vorbis viu — es tanca en JA_DeleteMusic.
|
||||
// Rebobinem perquè un futur JA_PlayMusic comence des del principi.
|
||||
if (current_music->vorbis) {
|
||||
stb_vorbis_seek_start(current_music->vorbis);
|
||||
}
|
||||
}
|
||||
|
||||
inline void JA_FadeOutMusic(const int milliseconds) {
|
||||
@@ -294,19 +384,23 @@ inline void JA_FadeOutMusic(const int milliseconds) {
|
||||
outgoing_music.stream = nullptr;
|
||||
}
|
||||
|
||||
// Pre-omplim l'stream amb `milliseconds` de so: un cop robat, ja no
|
||||
// tindrà accés al vorbis decoder i només podrà drenar el que tinga.
|
||||
JA_PreFillOutgoing(current_music, milliseconds);
|
||||
|
||||
// Robar el stream del current_music al outgoing
|
||||
outgoing_music.stream = current_music->stream;
|
||||
outgoing_music.fade = {true, SDL_GetTicks(), milliseconds, JA_musicVolume};
|
||||
|
||||
// Dejar current_music sin stream (ya lo tiene outgoing)
|
||||
current_music->stream = nullptr;
|
||||
current_music->pos = 0;
|
||||
current_music->state = JA_MUSIC_STOPPED;
|
||||
if (current_music->vorbis) stb_vorbis_seek_start(current_music->vorbis);
|
||||
incoming_fade.active = false;
|
||||
}
|
||||
|
||||
inline void JA_CrossfadeMusic(JA_Music_t* music, const int crossfade_ms, const int loop) {
|
||||
if (!JA_musicEnabled || !music) return;
|
||||
if (!JA_musicEnabled || !music || !music->vorbis) return;
|
||||
|
||||
// Destruir outgoing anterior si existe (crossfade durante crossfade)
|
||||
if (outgoing_music.stream) {
|
||||
@@ -315,28 +409,32 @@ inline void JA_CrossfadeMusic(JA_Music_t* music, const int crossfade_ms, const i
|
||||
outgoing_music.fade.active = false;
|
||||
}
|
||||
|
||||
// Robar el stream de la musica actual al outgoing para el fade-out
|
||||
// Robar el stream de la musica actual al outgoing para el fade-out.
|
||||
// Pre-omplim amb `crossfade_ms` de so perquè no es quede en silenci
|
||||
// abans d'acabar el fade (l'stream robat ja no pot alimentar-se).
|
||||
if (current_music && current_music->state == JA_MUSIC_PLAYING && current_music->stream) {
|
||||
JA_PreFillOutgoing(current_music, crossfade_ms);
|
||||
outgoing_music.stream = current_music->stream;
|
||||
outgoing_music.fade = {true, SDL_GetTicks(), crossfade_ms, JA_musicVolume};
|
||||
current_music->stream = nullptr;
|
||||
current_music->state = JA_MUSIC_STOPPED;
|
||||
if (current_music->vorbis) stb_vorbis_seek_start(current_music->vorbis);
|
||||
}
|
||||
|
||||
// Iniciar la nueva pista con gain=0 (el fade-in la sube gradualmente)
|
||||
current_music = music;
|
||||
current_music->pos = 0;
|
||||
current_music->state = JA_MUSIC_PLAYING;
|
||||
current_music->times = loop;
|
||||
|
||||
stb_vorbis_seek_start(current_music->vorbis);
|
||||
current_music->stream = SDL_CreateAudioStream(¤t_music->spec, &JA_audioSpec);
|
||||
if (!current_music->stream) {
|
||||
SDL_Log("Failed to create audio stream for crossfade!");
|
||||
current_music->state = JA_MUSIC_STOPPED;
|
||||
return;
|
||||
}
|
||||
SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length);
|
||||
SDL_SetAudioStreamGain(current_music->stream, 0.0f);
|
||||
JA_PumpMusic(current_music); // pre-carrega abans de bindejar
|
||||
SDL_BindAudioStream(sdlAudioDevice, current_music->stream);
|
||||
|
||||
// Configurar fade-in
|
||||
@@ -356,8 +454,9 @@ inline void JA_DeleteMusic(JA_Music_t* music) {
|
||||
JA_StopMusic();
|
||||
current_music = nullptr;
|
||||
}
|
||||
SDL_free(music->buffer);
|
||||
if (music->stream) SDL_DestroyAudioStream(music->stream);
|
||||
if (music->vorbis) stb_vorbis_close(music->vorbis);
|
||||
SDL_free(music->ogg_data);
|
||||
free(music->filename); // filename se libera aquí
|
||||
delete music;
|
||||
}
|
||||
@@ -370,17 +469,14 @@ inline float JA_SetMusicVolume(float volume) {
|
||||
return JA_musicVolume;
|
||||
}
|
||||
|
||||
inline void JA_SetMusicPosition(float value) {
|
||||
if (!current_music) return;
|
||||
current_music->pos = value * current_music->spec.freq;
|
||||
// Nota: Esta implementación de 'pos' no parece usarse en JA_Update para
|
||||
// el streaming. El streaming siempre parece empezar desde el principio.
|
||||
inline void JA_SetMusicPosition(float /*value*/) {
|
||||
// No implementat amb el backend de streaming. Mai va arribar a usar-se
|
||||
// en el codi existent, així que es manté com a stub.
|
||||
}
|
||||
|
||||
inline float JA_GetMusicPosition() {
|
||||
if (!current_music) return 0;
|
||||
return float(current_music->pos) / float(current_music->spec.freq);
|
||||
// Nota: Ver `JA_SetMusicPosition`
|
||||
// Veure nota a JA_SetMusicPosition.
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
inline void JA_EnableMusic(const bool value) {
|
||||
@@ -568,4 +664,4 @@ inline float JA_SetVolume(float volume) {
|
||||
float v = JA_SetMusicVolume(volume);
|
||||
JA_SetSoundVolume(v, -1); // Aplicar a todos los grupos de sonido
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,6 +492,7 @@ namespace Resource {
|
||||
|
||||
// Muestra el progreso de carga
|
||||
void Cache::renderProgress() {
|
||||
if (!Options::loading.show_progress) { return; }
|
||||
constexpr float X_PADDING = 60.0F;
|
||||
constexpr float Y_PADDING = 10.0F;
|
||||
constexpr float BAR_HEIGHT = 5.0F;
|
||||
|
||||
@@ -115,14 +115,14 @@ static auto sceneToString(SceneManager::Scene scene) -> std::string {
|
||||
|
||||
// Carga la configuración de debug desde debug.yaml
|
||||
void Debug::loadFromFile() {
|
||||
// Inicializar con valores de release por defecto
|
||||
spawn_settings_.room = Defaults::Game::Room::INITIAL;
|
||||
spawn_settings_.spawn_x = Defaults::Game::Player::SPAWN_X;
|
||||
spawn_settings_.spawn_y = Defaults::Game::Player::SPAWN_Y;
|
||||
spawn_settings_.flip = Defaults::Game::Player::SPAWN_FLIP;
|
||||
// Inicializar con valores por defecto de debug
|
||||
spawn_settings_.room = "902.yaml";
|
||||
spawn_settings_.spawn_x = 24 * Tile::SIZE;
|
||||
spawn_settings_.spawn_y = 13 * Tile::SIZE;
|
||||
spawn_settings_.flip = Flip::LEFT;
|
||||
initial_scene_ = SceneManager::Scene::GAME;
|
||||
lazy_loading_ = false;
|
||||
render_info_enabled_ = false;
|
||||
render_info_enabled_ = true;
|
||||
|
||||
std::ifstream file(debug_file_path_);
|
||||
if (!file.good()) {
|
||||
@@ -166,14 +166,14 @@ void Debug::loadFromFile() {
|
||||
render_info_enabled_ = yaml["render_info"].get_value<bool>();
|
||||
}
|
||||
} catch (...) {
|
||||
// YAML inválido: resetear a defaults y sobreescribir
|
||||
spawn_settings_.room = Defaults::Game::Room::INITIAL;
|
||||
spawn_settings_.spawn_x = Defaults::Game::Player::SPAWN_X;
|
||||
spawn_settings_.spawn_y = Defaults::Game::Player::SPAWN_Y;
|
||||
spawn_settings_.flip = Defaults::Game::Player::SPAWN_FLIP;
|
||||
// YAML inválido: resetear a defaults de debug y sobreescribir
|
||||
spawn_settings_.room = "902.yaml";
|
||||
spawn_settings_.spawn_x = 24 * Tile::SIZE;
|
||||
spawn_settings_.spawn_y = 13 * Tile::SIZE;
|
||||
spawn_settings_.flip = Flip::LEFT;
|
||||
initial_scene_ = SceneManager::Scene::GAME;
|
||||
lazy_loading_ = false;
|
||||
render_info_enabled_ = false;
|
||||
render_info_enabled_ = true;
|
||||
saveToFile();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Defaults::Canvas {
|
||||
} // namespace Defaults::Canvas
|
||||
|
||||
namespace Defaults::Window {
|
||||
constexpr int ZOOM = 2; // Zoom de la ventana por defecto
|
||||
constexpr int ZOOM = 3; // Zoom de la ventana por defecto
|
||||
} // namespace Defaults::Window
|
||||
|
||||
namespace Defaults::Video {
|
||||
@@ -114,6 +114,10 @@ namespace Defaults::Console {
|
||||
constexpr Uint8 COMMAND_COLOR = 9; // Color del texto que escribe el usuario
|
||||
} // namespace Defaults::Console
|
||||
|
||||
namespace Defaults::Loading {
|
||||
constexpr bool SHOW_PROGRESS = false; // Por defecto no mostrar la barra de carga de recursos
|
||||
} // namespace Defaults::Loading
|
||||
|
||||
namespace Defaults::Localization {
|
||||
constexpr const char* LANGUAGE = "ca"; // Idioma por defecto (en = inglés, ca = catalán)
|
||||
} // namespace Defaults::Localization
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#include "game/entities/key.hpp"
|
||||
|
||||
#include <cmath> // Para std::sin
|
||||
|
||||
#include "core/rendering/sprite/animated_sprite.hpp" // Para AnimatedSprite
|
||||
#include "core/resources/resource_cache.hpp" // Para Resource
|
||||
|
||||
// Constructor: carga la animación, posiciona el sprite y crea el collider
|
||||
Key::Key(const Data& data)
|
||||
: sprite_(std::make_shared<AnimatedSprite>(Resource::Cache::get()->getAnimationData(data.animation_path))),
|
||||
id_(data.id) {
|
||||
id_(data.id),
|
||||
base_y_(data.y) {
|
||||
sprite_->setPosX(data.x);
|
||||
sprite_->setPosY(data.y);
|
||||
sprite_->setCurrentAnimation("default");
|
||||
@@ -18,17 +21,22 @@ void Key::render() {
|
||||
sprite_->render();
|
||||
}
|
||||
|
||||
// Avanza la animación de la llave
|
||||
// Avanza la animación de la llave y aplica el movimiento flotante sinusoidal
|
||||
void Key::update(float delta_time) {
|
||||
if (is_paused_) {
|
||||
return;
|
||||
}
|
||||
sprite_->animate(delta_time);
|
||||
|
||||
// Oscilacion sinusoidal sincronizada (mismo tiempo global para todas las llaves)
|
||||
const float t = static_cast<float>(SDL_GetTicks()) / 1000.0F;
|
||||
const float offset = std::sin(t * 2.0F * SDL_PI_F / FLOAT_PERIOD_S) * FLOAT_AMPLITUDE;
|
||||
sprite_->setPosY(base_y_ + offset);
|
||||
}
|
||||
|
||||
// Posición actual (para registrar pickup en KeyTracker)
|
||||
// Posición base (el collider y el tracker usan la posición sin oscilación)
|
||||
auto Key::getPos() const -> SDL_FPoint {
|
||||
return SDL_FPoint{.x = sprite_->getX(), .y = sprite_->getY()};
|
||||
return SDL_FPoint{.x = sprite_->getX(), .y = base_y_};
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
@@ -36,6 +44,7 @@ auto Key::getPos() const -> SDL_FPoint {
|
||||
void Key::setPosition(float x, float y) {
|
||||
sprite_->setPosX(x);
|
||||
sprite_->setPosY(y);
|
||||
base_y_ = y;
|
||||
collider_ = sprite_->getRect();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -24,6 +24,9 @@ class Key {
|
||||
float y{0.0F}; // Posición Y en píxeles
|
||||
};
|
||||
|
||||
static constexpr float FLOAT_PERIOD_S = 2.0F; // Segundos por ciclo sinusoidal (todas las llaves sincronizadas)
|
||||
static constexpr float FLOAT_AMPLITUDE = 2.0F; // Amplitud en píxeles
|
||||
|
||||
explicit Key(const Data& data);
|
||||
~Key() = default;
|
||||
|
||||
@@ -44,5 +47,6 @@ class Key {
|
||||
std::shared_ptr<AnimatedSprite> sprite_; // Sprite animado de la llave
|
||||
SDL_FRect collider_{}; // Rectángulo de colisión
|
||||
std::string id_; // Identificador
|
||||
float base_y_{0.0F}; // Posición Y base (el sprite oscila alrededor)
|
||||
bool is_paused_{false}; // Indica si la llave está pausada
|
||||
};
|
||||
|
||||
@@ -631,6 +631,19 @@ namespace Options {
|
||||
}
|
||||
}
|
||||
|
||||
// Carga configuración de la pantalla de carga de recursos desde YAML
|
||||
void loadLoadingConfigFromYaml(const fkyaml::node& yaml) {
|
||||
if (!yaml.contains("loading")) { return; }
|
||||
const auto& l = yaml["loading"];
|
||||
|
||||
if (l.contains("show_progress")) {
|
||||
try {
|
||||
loading.show_progress = l["show_progress"].get_value<bool>();
|
||||
} catch (...) { /* @INTENTIONAL: campo yaml ausente o malformado → dejar default */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Carga configuración de idioma desde YAML
|
||||
void loadLocalizationFromYaml(const fkyaml::node& yaml) {
|
||||
if (yaml.contains("localization")) {
|
||||
@@ -696,6 +709,7 @@ namespace Options {
|
||||
loadKioskConfigFromYaml(yaml);
|
||||
loadLocalizationFromYaml(yaml);
|
||||
loadConsoleConfigFromYaml(yaml);
|
||||
loadLoadingConfigFromYaml(yaml);
|
||||
|
||||
std::cout << "Config file loaded successfully\n\n";
|
||||
|
||||
@@ -832,6 +846,12 @@ namespace Options {
|
||||
file << " text: \"" << kiosk.text << "\"\n";
|
||||
file << " infinite_lives: " << (kiosk.infinite_lives ? "true" : "false") << "\n";
|
||||
|
||||
// LOADING
|
||||
file << "\n";
|
||||
file << "# LOADING (pantalla de carga de recursos)\n";
|
||||
file << "loading:\n";
|
||||
file << " show_progress: " << (loading.show_progress ? "true" : "false") << " # mostrar barra de progreso al cargar recursos\n";
|
||||
|
||||
// LOCALIZATION
|
||||
file << "\n";
|
||||
file << "# LOCALIZATION (en = English, ca = Catalan)\n";
|
||||
|
||||
@@ -138,6 +138,11 @@ namespace Options {
|
||||
float height{Defaults::Canvas::HEIGHT}; // Alto de la resolucion del juego
|
||||
};
|
||||
|
||||
// Estructura para las opciones de la pantalla de carga de recursos
|
||||
struct Loading {
|
||||
bool show_progress{Defaults::Loading::SHOW_PROGRESS}; // Mostrar barra de progreso al cargar recursos
|
||||
};
|
||||
|
||||
// Estructura para las opciones visuales de la consola en pantalla
|
||||
struct Console {
|
||||
bool transparent{Defaults::Console::TRANSPARENT}; // true = sin fondo, false = sólida
|
||||
@@ -191,6 +196,7 @@ namespace Options {
|
||||
inline GamepadControls gamepad_controls{}; // Botones del gamepad usados para jugar
|
||||
inline Kiosk kiosk{}; // Opciones del modo kiosko
|
||||
inline Console console{}; // Opciones visuales de la consola en pantalla
|
||||
inline Loading loading{}; // Opciones de la pantalla de carga de recursos
|
||||
|
||||
// Idioma del juego (establecido al inicio, sin cambio en caliente)
|
||||
inline std::string language{Defaults::Localization::LANGUAGE};
|
||||
|
||||
Reference in New Issue
Block a user