ajustant el jugador
This commit is contained in:
28
CLAUDE.md
28
CLAUDE.md
@@ -18,11 +18,37 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
## Estado del renombrado
|
## Estado del renombrado
|
||||||
|
|
||||||
Se han renombrado las referencias de `JailDoctor's Dilemma` → `Projecte 2026` y `jaildoctors_dilemma` → `projecte_2026` en código, configs, Makefile, CMake, LICENSE, Info.plist, scripts, locales, etc. Se han mantenido como placeholders:
|
Se han renombrado las referencias de `JailDoctor's Dilemma` → `Projecte 2026` y `jaildoctors_dilemma` → `projecte_2026` en código, configs, Makefile, CMake, LICENSE, Info.plist, scripts, locales, etc. Copyright actualizado a 2026. Se han mantenido como placeholders:
|
||||||
- La clave de locale `jaildoctor:` en `data/locale/*.yaml` y su uso en `source/game/scenes/ending2.cpp` (es contenido de juego, pendiente de rediseño).
|
- La clave de locale `jaildoctor:` en `data/locale/*.yaml` y su uso en `source/game/scenes/ending2.cpp` (es contenido de juego, pendiente de rediseño).
|
||||||
- El publisher `jailgames` (carpeta de config de sistema: `~/.config/jailgames/projecte_2026`).
|
- El publisher `jailgames` (carpeta de config de sistema: `~/.config/jailgames/projecte_2026`).
|
||||||
- Los archivos `release/windows/jdd.rc` y `jdd.res` (solo bundlean el icono).
|
- Los archivos `release/windows/jdd.rc` y `jdd.res` (solo bundlean el icono).
|
||||||
|
|
||||||
|
## Log de cambios realizados (sesiones de trabajo)
|
||||||
|
|
||||||
|
### Eliminaciones
|
||||||
|
- **Clase `Stats` (persistencia CSV de muertes/visitas)** eliminada por completo: archivos `source/game/gameplay/stats.hpp/cpp`, entrada en CMakeLists, referencias en `Game` scene (`stats_`, `initStats()`, `addVisit/addDeath`), ficheros `stats.csv`/`stats_buffer.csv` en `config/assets.yaml`, patrón `*stats.txt` en `.gitignore`, campo `worst_nightmare` en `Options::Stats` + `Defaults::Stats::WORST_NIGHTMARE`, display de "worst nightmare" en `game_over.cpp`/`.hpp`, traducciones en locales, menciones en docs.
|
||||||
|
- **Mantenido:** `Options::stats.items` y `Options::stats.rooms` — son contadores de runtime del marcador/game_over, no tienen persistencia CSV. Coincidencia de nombre con la clase Stats eliminada.
|
||||||
|
|
||||||
|
### Música
|
||||||
|
- Eliminadas las 10 pistas originales (14 MB) de `data/music/`.
|
||||||
|
- Copiadas 2 pistas de `../pollo/data/music/`: `574070_KUVO_Farewell_to_school.ogg` y `574071_EA_DTV.ogg` (7 MB total).
|
||||||
|
- `config/assets.yaml` reducido a esas 2 entradas.
|
||||||
|
- Las 10 llamadas `playMusic()` existentes (title/game/loading_*/ending*/game_over) remapeadas alternadamente a una de las 2 pistas. Mapeo concreto en esta misma documentación si hace falta consultarlo (ver git log del cambio).
|
||||||
|
|
||||||
|
### Paleta
|
||||||
|
- Eliminadas las 23 paletas ZX Spectrum/otras de `data/palette/`.
|
||||||
|
- Traída `cpc.pal` de `../pollo/data/palettes/` (JASC-PAL, 28 entradas: CLEAR+27 colores CPC).
|
||||||
|
- `config/assets.yaml`: solo `cpc.pal`.
|
||||||
|
- `Defaults::Video::PALETTE_NAME = "cpc"`.
|
||||||
|
- Traída la clase `Color` de pollo a `source/utils/color.hpp` + `color.cpp` (enum `Color::Cpc` con 28 valores 0-27 + `Color::fromString()`).
|
||||||
|
- Struct RGB `Color` en `utils.hpp` **renombrada a `Rgb`** para evitar conflicto con la nueva clase. Propagado a `utils.cpp` (`colorAreEqual`), `screen.hpp`/`.cpp` (`clearRenderer`).
|
||||||
|
- Añadido `source/utils/color.cpp` a `CMakeLists.txt`.
|
||||||
|
- **Pendiente de revisar:** enum `PaletteColor` en `utils.hpp` sigue con los 16 índices antiguos (ZX Spectrum). Los índices 0-4 coinciden con CPC, pero 5+ mapean a colores diferentes (ej. `PaletteColor::BRIGHT_RED=5` ahora renderiza MAGENTA en CPC). `stringToColor()` también sin actualizar. `SPECTRUM_REFERENCE` en `palette_manager.cpp` sigue siendo la referencia ZX Spectrum de 16 colores. Falta decidir cómo migrar estos tres puntos cuando se vea el resultado visual.
|
||||||
|
- **`next()`/`previous()` en PaletteManager**: con una sola paleta hacen wrap al mismo índice (no crashean). El concepto de ciclar paletas queda desactivado de facto; posible futura reutilización para ciclar modos de ordenación.
|
||||||
|
|
||||||
|
### Otros
|
||||||
|
- Añadidos `desktop.ini` y `Thumbs.db` al `.gitignore`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Overview (legacy)
|
## Overview (legacy)
|
||||||
|
|||||||
@@ -252,11 +252,9 @@ assets:
|
|||||||
player:
|
player:
|
||||||
BITMAP:
|
BITMAP:
|
||||||
- ${PREFIX}/data/player/player.gif
|
- ${PREFIX}/data/player/player.gif
|
||||||
- ${PREFIX}/data/player/player2.gif
|
|
||||||
- ${PREFIX}/data/player/player_game_over.gif
|
- ${PREFIX}/data/player/player_game_over.gif
|
||||||
ANIMATION:
|
ANIMATION:
|
||||||
- ${PREFIX}/data/player/player.yaml
|
- ${PREFIX}/data/player/player.yaml
|
||||||
- ${PREFIX}/data/player/player2.yaml
|
|
||||||
- ${PREFIX}/data/player/player_game_over.yaml
|
- ${PREFIX}/data/player/player_game_over.yaml
|
||||||
|
|
||||||
# ITEMS
|
# ITEMS
|
||||||
@@ -276,30 +274,8 @@ assets:
|
|||||||
- ${PREFIX}/data/sound/item.wav
|
- ${PREFIX}/data/sound/item.wav
|
||||||
- ${PREFIX}/data/sound/death.wav
|
- ${PREFIX}/data/sound/death.wav
|
||||||
- ${PREFIX}/data/sound/notify.wav
|
- ${PREFIX}/data/sound/notify.wav
|
||||||
- ${PREFIX}/data/sound/jump1.wav
|
- ${PREFIX}/data/sound/jump.wav
|
||||||
- ${PREFIX}/data/sound/jump2.wav
|
- ${PREFIX}/data/sound/land.wav
|
||||||
- ${PREFIX}/data/sound/jump3.wav
|
|
||||||
- ${PREFIX}/data/sound/jump4.wav
|
|
||||||
- ${PREFIX}/data/sound/jump5.wav
|
|
||||||
- ${PREFIX}/data/sound/jump6.wav
|
|
||||||
- ${PREFIX}/data/sound/jump7.wav
|
|
||||||
- ${PREFIX}/data/sound/jump8.wav
|
|
||||||
- ${PREFIX}/data/sound/jump9.wav
|
|
||||||
- ${PREFIX}/data/sound/jump10.wav
|
|
||||||
- ${PREFIX}/data/sound/jump11.wav
|
|
||||||
- ${PREFIX}/data/sound/jump12.wav
|
|
||||||
- ${PREFIX}/data/sound/jump13.wav
|
|
||||||
- ${PREFIX}/data/sound/jump14.wav
|
|
||||||
- ${PREFIX}/data/sound/jump15.wav
|
|
||||||
- ${PREFIX}/data/sound/jump16.wav
|
|
||||||
- ${PREFIX}/data/sound/jump17.wav
|
|
||||||
- ${PREFIX}/data/sound/jump18.wav
|
|
||||||
- ${PREFIX}/data/sound/jump19.wav
|
|
||||||
- ${PREFIX}/data/sound/jump20.wav
|
|
||||||
- ${PREFIX}/data/sound/jump21.wav
|
|
||||||
- ${PREFIX}/data/sound/jump22.wav
|
|
||||||
- ${PREFIX}/data/sound/jump23.wav
|
|
||||||
- ${PREFIX}/data/sound/jump24.wav
|
|
||||||
|
|
||||||
# LOGO
|
# LOGO
|
||||||
logo:
|
logo:
|
||||||
|
|||||||
BIN
data/player/player.aseprite
Normal file
BIN
data/player/player.aseprite
Normal file
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 145 B After Width: | Height: | Size: 323 B |
@@ -4,7 +4,17 @@ frameWidth: 8
|
|||||||
frameHeight: 16
|
frameHeight: 16
|
||||||
|
|
||||||
animations:
|
animations:
|
||||||
|
- name: stand
|
||||||
|
speed: 0
|
||||||
|
loop: -1
|
||||||
|
frames: [0]
|
||||||
|
|
||||||
- name: default
|
- name: default
|
||||||
speed: 0.1333
|
speed: 0.07
|
||||||
loop: 0
|
loop: 0
|
||||||
frames: [0, 1, 2, 3]
|
frames: [0, 1, 2, 3]
|
||||||
|
|
||||||
|
- name: jump
|
||||||
|
speed: 0
|
||||||
|
loop: -1
|
||||||
|
frames: [4]
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 223 B |
@@ -1,10 +0,0 @@
|
|||||||
# player2 animation
|
|
||||||
tileSetFile: player2.gif
|
|
||||||
frameWidth: 8
|
|
||||||
frameHeight: 16
|
|
||||||
|
|
||||||
animations:
|
|
||||||
- name: default
|
|
||||||
speed: 0.1333
|
|
||||||
loop: 0
|
|
||||||
frames: [0, 1, 2, 3, 4, 5, 6, 7]
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
# VOID MAIN
|
# VOID MAIN
|
||||||
room:
|
room:
|
||||||
name_en: "VOID MAIN"
|
|
||||||
name_ca: "VOID MAIN"
|
name_ca: "VOID MAIN"
|
||||||
|
name_en: "VOID MAIN"
|
||||||
bgColor: black
|
bgColor: black
|
||||||
border: magenta
|
border: bright_black
|
||||||
tileSetFile: standard.gif
|
tileSetFile: standard.gif
|
||||||
|
|
||||||
# Conexiones de la habitación (null = sin conexión)
|
# Conexiones de la habitación (null = sin conexión)
|
||||||
@@ -44,7 +44,7 @@ tilemap:
|
|||||||
enemies:
|
enemies:
|
||||||
- animation: code.yaml
|
- animation: code.yaml
|
||||||
position: {x: 3, y: 2}
|
position: {x: 3, y: 2}
|
||||||
velocity: {x: 24.0, y: 0}
|
velocity: {x: 24, y: 0}
|
||||||
boundaries:
|
boundaries:
|
||||||
position1: {x: 3, y: 2}
|
position1: {x: 3, y: 2}
|
||||||
position2: {x: 27, y: 2}
|
position2: {x: 27, y: 2}
|
||||||
@@ -56,3 +56,4 @@ items:
|
|||||||
tile: 42
|
tile: 42
|
||||||
position: {x: 21, y: 13}
|
position: {x: 21, y: 13}
|
||||||
counter: 1
|
counter: 1
|
||||||
|
|
||||||
|
|||||||
BIN
data/sound/jump.wav
Normal file
BIN
data/sound/jump.wav
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -30,10 +30,10 @@ class Screen {
|
|||||||
|
|
||||||
// Renderizado
|
// Renderizado
|
||||||
void clearRenderer(Rgb color = {0x00, 0x00, 0x00}); // Limpia el renderer
|
void clearRenderer(Rgb color = {0x00, 0x00, 0x00}); // Limpia el renderer
|
||||||
void clearSurface(Uint8 index); // Limpia la game_surface_
|
void clearSurface(Uint8 index); // Limpia la game_surface_
|
||||||
void start(); // Prepara para empezar a dibujar en la textura de juego
|
void start(); // Prepara para empezar a dibujar en la textura de juego
|
||||||
void render(); // Vuelca el contenido del renderizador en pantalla
|
void render(); // Vuelca el contenido del renderizador en pantalla
|
||||||
void update(float delta_time); // Actualiza la lógica de la clase
|
void update(float delta_time); // Actualiza la lógica de la clase
|
||||||
|
|
||||||
// Video y ventana
|
// Video y ventana
|
||||||
void setVideoMode(bool mode); // Establece el modo de video
|
void setVideoMode(bool mode); // Establece el modo de video
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace Resource {
|
|||||||
Cache* Cache::cache = nullptr;
|
Cache* Cache::cache = nullptr;
|
||||||
|
|
||||||
// [SINGLETON] Crearemos el objeto cache con esta función estática
|
// [SINGLETON] Crearemos el objeto cache con esta función estática
|
||||||
void Cache::init() { Cache::cache = new Cache(); }
|
void Cache::init(LoadingMode mode) { Cache::cache = new Cache(mode); }
|
||||||
|
|
||||||
// [SINGLETON] Destruiremos el objeto cache con esta función estática
|
// [SINGLETON] Destruiremos el objeto cache con esta función estática
|
||||||
void Cache::destroy() { delete Cache::cache; }
|
void Cache::destroy() { delete Cache::cache; }
|
||||||
@@ -39,8 +39,8 @@ namespace Resource {
|
|||||||
auto Cache::get() -> Cache* { return Cache::cache; }
|
auto Cache::get() -> Cache* { return Cache::cache; }
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Cache::Cache()
|
Cache::Cache(LoadingMode mode)
|
||||||
: loading_text_(Screen::get()->getText()) {
|
: loading_mode_(mode), loading_text_(Screen::get()->getText()) {
|
||||||
load();
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,18 +59,25 @@ namespace Resource {
|
|||||||
void Cache::load() {
|
void Cache::load() {
|
||||||
// Nota: el overlay de debug (RenderInfo) se inicializa después de esta carga,
|
// Nota: el overlay de debug (RenderInfo) se inicializa después de esta carga,
|
||||||
// por lo que updateZoomFactor() se llamará correctamente en RenderInfo::init().
|
// por lo que updateZoomFactor() se llamará correctamente en RenderInfo::init().
|
||||||
calculateTotal();
|
if (loading_mode_ == LoadingMode::EAGER) {
|
||||||
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
|
calculateTotal();
|
||||||
std::cout << "\n** LOADING RESOURCES" << '\n';
|
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
|
||||||
loadSounds();
|
std::cout << "\n** LOADING RESOURCES" << '\n';
|
||||||
loadMusics();
|
loadSounds();
|
||||||
loadSurfaces();
|
loadMusics();
|
||||||
loadPalettes();
|
loadSurfaces();
|
||||||
loadTextFiles();
|
loadPalettes();
|
||||||
loadAnimations();
|
loadTextFiles();
|
||||||
loadRooms();
|
loadAnimations();
|
||||||
createText();
|
loadRooms();
|
||||||
std::cout << "\n** RESOURCES LOADED" << '\n';
|
createText();
|
||||||
|
std::cout << "\n** RESOURCES LOADED" << '\n';
|
||||||
|
} else {
|
||||||
|
std::cout << "\n** LAZY LOADING MODE **\n";
|
||||||
|
initLazyStubs();
|
||||||
|
createText(); // Carga fuentes bajo demanda a través de los getters lazy
|
||||||
|
std::cout << "\n** RESOURCE STUBS READY" << '\n';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recarga todos los recursos
|
// Recarga todos los recursos
|
||||||
@@ -80,10 +87,13 @@ namespace Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Obtiene el sonido a partir de un nombre
|
// Obtiene el sonido a partir de un nombre
|
||||||
auto Cache::getSound(const std::string& name) -> JA_Sound_t* { // NOLINT(readability-convert-member-functions-to-static)
|
auto Cache::getSound(const std::string& name) -> JA_Sound_t* {
|
||||||
auto it = std::ranges::find_if(sounds_, [&name](const auto& s) -> bool { return s.name == name; });
|
auto it = std::ranges::find_if(sounds_, [&name](const auto& s) -> bool { return s.name == name; });
|
||||||
|
|
||||||
if (it != sounds_.end()) {
|
if (it != sounds_.end()) {
|
||||||
|
if (loading_mode_ == LoadingMode::LAZY && it->sound == nullptr) {
|
||||||
|
loadSoundByName(name);
|
||||||
|
}
|
||||||
return it->sound;
|
return it->sound;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,10 +102,13 @@ namespace Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Obtiene la música a partir de un nombre
|
// Obtiene la música a partir de un nombre
|
||||||
auto Cache::getMusic(const std::string& name) -> JA_Music_t* { // NOLINT(readability-convert-member-functions-to-static)
|
auto Cache::getMusic(const std::string& name) -> JA_Music_t* {
|
||||||
auto it = std::ranges::find_if(musics_, [&name](const auto& m) -> bool { return m.name == name; });
|
auto it = std::ranges::find_if(musics_, [&name](const auto& m) -> bool { return m.name == name; });
|
||||||
|
|
||||||
if (it != musics_.end()) {
|
if (it != musics_.end()) {
|
||||||
|
if (loading_mode_ == LoadingMode::LAZY && it->music == nullptr) {
|
||||||
|
loadMusicByName(name);
|
||||||
|
}
|
||||||
return it->music;
|
return it->music;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,10 +117,13 @@ namespace Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Obtiene la surface a partir de un nombre
|
// Obtiene la surface a partir de un nombre
|
||||||
auto Cache::getSurface(const std::string& name) -> std::shared_ptr<Surface> { // NOLINT(readability-convert-member-functions-to-static)
|
auto Cache::getSurface(const std::string& name) -> std::shared_ptr<Surface> {
|
||||||
auto it = std::ranges::find_if(surfaces_, [&name](const auto& t) -> bool { return t.name == name; });
|
auto it = std::ranges::find_if(surfaces_, [&name](const auto& t) -> bool { return t.name == name; });
|
||||||
|
|
||||||
if (it != surfaces_.end()) {
|
if (it != surfaces_.end()) {
|
||||||
|
if (loading_mode_ == LoadingMode::LAZY && it->surface == nullptr) {
|
||||||
|
loadSurfaceByName(name);
|
||||||
|
}
|
||||||
return it->surface;
|
return it->surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,10 +132,13 @@ namespace Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Obtiene la paleta a partir de un nombre
|
// Obtiene la paleta a partir de un nombre
|
||||||
auto Cache::getPalette(const std::string& name) -> Palette { // NOLINT(readability-convert-member-functions-to-static)
|
auto Cache::getPalette(const std::string& name) -> Palette {
|
||||||
auto it = std::ranges::find_if(palettes_, [&name](const auto& t) -> bool { return t.name == name; });
|
auto it = std::ranges::find_if(palettes_, [&name](const auto& t) -> bool { return t.name == name; });
|
||||||
|
|
||||||
if (it != palettes_.end()) {
|
if (it != palettes_.end()) {
|
||||||
|
if (loading_mode_ == LoadingMode::LAZY && !it->loaded) {
|
||||||
|
loadPaletteByName(name);
|
||||||
|
}
|
||||||
return it->palette;
|
return it->palette;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,10 +147,13 @@ namespace Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Obtiene el fichero de texto a partir de un nombre
|
// Obtiene el fichero de texto a partir de un nombre
|
||||||
auto Cache::getTextFile(const std::string& name) -> std::shared_ptr<Text::File> { // NOLINT(readability-convert-member-functions-to-static)
|
auto Cache::getTextFile(const std::string& name) -> std::shared_ptr<Text::File> {
|
||||||
auto it = std::ranges::find_if(text_files_, [&name](const auto& t) -> bool { return t.name == name; });
|
auto it = std::ranges::find_if(text_files_, [&name](const auto& t) -> bool { return t.name == name; });
|
||||||
|
|
||||||
if (it != text_files_.end()) {
|
if (it != text_files_.end()) {
|
||||||
|
if (loading_mode_ == LoadingMode::LAZY && it->text_file == nullptr) {
|
||||||
|
loadTextFileByName(name);
|
||||||
|
}
|
||||||
return it->text_file;
|
return it->text_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,10 +174,13 @@ namespace Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Obtiene los datos de animación parseados a partir de un nombre
|
// Obtiene los datos de animación parseados a partir de un nombre
|
||||||
auto Cache::getAnimationData(const std::string& name) -> const AnimationResource& { // NOLINT(readability-convert-member-functions-to-static)
|
auto Cache::getAnimationData(const std::string& name) -> const AnimationResource& {
|
||||||
auto it = std::ranges::find_if(animations_, [&name](const auto& a) -> bool { return a.name == name; });
|
auto it = std::ranges::find_if(animations_, [&name](const auto& a) -> bool { return a.name == name; });
|
||||||
|
|
||||||
if (it != animations_.end()) {
|
if (it != animations_.end()) {
|
||||||
|
if (loading_mode_ == LoadingMode::LAZY && it->yaml_data.empty()) {
|
||||||
|
loadAnimationByName(name);
|
||||||
|
}
|
||||||
return *it;
|
return *it;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,10 +189,13 @@ namespace Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Obtiene la habitación a partir de un nombre
|
// Obtiene la habitación a partir de un nombre
|
||||||
auto Cache::getRoom(const std::string& name) -> std::shared_ptr<Room::Data> { // NOLINT(readability-convert-member-functions-to-static)
|
auto Cache::getRoom(const std::string& name) -> std::shared_ptr<Room::Data> {
|
||||||
auto it = std::ranges::find_if(rooms_, [&name](const auto& r) -> bool { return r.name == name; });
|
auto it = std::ranges::find_if(rooms_, [&name](const auto& r) -> bool { return r.name == name; });
|
||||||
|
|
||||||
if (it != rooms_.end()) {
|
if (it != rooms_.end()) {
|
||||||
|
if (loading_mode_ == LoadingMode::LAZY && it->room == nullptr) {
|
||||||
|
loadRoomByName(name);
|
||||||
|
}
|
||||||
return it->room;
|
return it->room;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,6 +233,11 @@ namespace Resource {
|
|||||||
|
|
||||||
// Obtiene todas las habitaciones
|
// Obtiene todas las habitaciones
|
||||||
auto Cache::getRooms() -> std::vector<RoomResource>& {
|
auto Cache::getRooms() -> std::vector<RoomResource>& {
|
||||||
|
if (loading_mode_ == LoadingMode::LAZY) {
|
||||||
|
for (auto& r : rooms_) {
|
||||||
|
if (r.room == nullptr) { loadRoomByName(r.name); }
|
||||||
|
}
|
||||||
|
}
|
||||||
return rooms_;
|
return rooms_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,4 +563,144 @@ namespace Resource {
|
|||||||
checkEvents();
|
checkEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Modo lazy: stubs y cargadores bajo demanda ---------------------------
|
||||||
|
|
||||||
|
// Rellena los vectores de recursos con entradas name-only (sin contenido)
|
||||||
|
void Cache::initLazyStubs() {
|
||||||
|
sounds_.clear();
|
||||||
|
musics_.clear();
|
||||||
|
surfaces_.clear();
|
||||||
|
palettes_.clear();
|
||||||
|
text_files_.clear();
|
||||||
|
animations_.clear();
|
||||||
|
rooms_.clear();
|
||||||
|
|
||||||
|
for (const auto& l : List::get()->getListByType(List::Type::SOUND)) {
|
||||||
|
sounds_.emplace_back(SoundResource{.name = getFileName(l), .sound = nullptr});
|
||||||
|
}
|
||||||
|
for (const auto& l : List::get()->getListByType(List::Type::MUSIC)) {
|
||||||
|
musics_.emplace_back(MusicResource{.name = getFileName(l), .music = nullptr});
|
||||||
|
}
|
||||||
|
for (const auto& l : List::get()->getListByType(List::Type::BITMAP)) {
|
||||||
|
surfaces_.emplace_back(SurfaceResource{.name = getFileName(l), .surface = nullptr});
|
||||||
|
}
|
||||||
|
for (const auto& l : List::get()->getListByType(List::Type::PALETTE)) {
|
||||||
|
palettes_.emplace_back(ResourcePalette{.name = getFileName(l)});
|
||||||
|
}
|
||||||
|
for (const auto& l : List::get()->getListByType(List::Type::FONT)) {
|
||||||
|
text_files_.emplace_back(TextFileResource{.name = getFileName(l), .text_file = nullptr});
|
||||||
|
}
|
||||||
|
for (const auto& l : List::get()->getListByType(List::Type::ANIMATION)) {
|
||||||
|
animations_.emplace_back(AnimationResource{.name = getFileName(l), .yaml_data = {}});
|
||||||
|
}
|
||||||
|
for (const auto& l : List::get()->getListByType(List::Type::ROOM)) {
|
||||||
|
rooms_.emplace_back(RoomResource{.name = getFileName(l), .room = nullptr});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cache::loadSoundByName(const std::string& name) {
|
||||||
|
auto it = std::ranges::find_if(sounds_, [&name](const auto& s) { return s.name == name; });
|
||||||
|
if (it == sounds_.end()) { return; }
|
||||||
|
auto path = List::get()->get(name);
|
||||||
|
try {
|
||||||
|
auto bytes = Helper::loadFile(path);
|
||||||
|
JA_Sound_t* sound = nullptr;
|
||||||
|
if (!bytes.empty()) { sound = JA_LoadSound(bytes.data(), static_cast<Uint32>(bytes.size())); }
|
||||||
|
if (sound == nullptr) { sound = JA_LoadSound(path.c_str()); }
|
||||||
|
if (sound == nullptr) { throw std::runtime_error("Failed to decode audio file"); }
|
||||||
|
it->sound = sound;
|
||||||
|
std::cout << "[lazy] Sound loaded: " << name << '\n';
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throwLoadError("SOUND", path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cache::loadMusicByName(const std::string& name) {
|
||||||
|
auto it = std::ranges::find_if(musics_, [&name](const auto& m) { return m.name == name; });
|
||||||
|
if (it == musics_.end()) { return; }
|
||||||
|
auto path = List::get()->get(name);
|
||||||
|
try {
|
||||||
|
auto bytes = Helper::loadFile(path);
|
||||||
|
JA_Music_t* music = nullptr;
|
||||||
|
if (!bytes.empty()) { music = JA_LoadMusic(bytes.data(), static_cast<Uint32>(bytes.size())); }
|
||||||
|
if (music == nullptr) { music = JA_LoadMusic(path.c_str()); }
|
||||||
|
if (music == nullptr) { throw std::runtime_error("Failed to decode music file"); }
|
||||||
|
it->music = music;
|
||||||
|
std::cout << "[lazy] Music loaded: " << name << '\n';
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throwLoadError("MUSIC", path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cache::loadSurfaceByName(const std::string& name) {
|
||||||
|
auto it = std::ranges::find_if(surfaces_, [&name](const auto& s) { return s.name == name; });
|
||||||
|
if (it == surfaces_.end()) { return; }
|
||||||
|
auto path = List::get()->get(name);
|
||||||
|
try {
|
||||||
|
it->surface = std::make_shared<Surface>(path);
|
||||||
|
it->surface->setTransparentColor(0);
|
||||||
|
// Superficies con color transparente específico (replica el ajuste de loadSurfaces)
|
||||||
|
if (name == "loading_screen_color.gif" || name == "ending1.gif" || name == "ending2.gif" ||
|
||||||
|
name == "ending3.gif" || name == "ending4.gif" || name == "ending5.gif") {
|
||||||
|
it->surface->setTransparentColor();
|
||||||
|
} else if (name == "standard.gif") {
|
||||||
|
it->surface->setTransparentColor(16);
|
||||||
|
}
|
||||||
|
std::cout << "[lazy] Surface loaded: " << name << '\n';
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throwLoadError("BITMAP", path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cache::loadPaletteByName(const std::string& name) {
|
||||||
|
auto it = std::ranges::find_if(palettes_, [&name](const auto& p) { return p.name == name; });
|
||||||
|
if (it == palettes_.end()) { return; }
|
||||||
|
auto path = List::get()->get(name);
|
||||||
|
try {
|
||||||
|
it->palette = readPalFile(path);
|
||||||
|
it->loaded = true;
|
||||||
|
std::cout << "[lazy] Palette loaded: " << name << '\n';
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throwLoadError("PALETTE", path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cache::loadTextFileByName(const std::string& name) {
|
||||||
|
auto it = std::ranges::find_if(text_files_, [&name](const auto& t) { return t.name == name; });
|
||||||
|
if (it == text_files_.end()) { return; }
|
||||||
|
auto path = List::get()->get(name);
|
||||||
|
try {
|
||||||
|
it->text_file = Text::loadTextFile(path);
|
||||||
|
std::cout << "[lazy] TextFile loaded: " << name << '\n';
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throwLoadError("FONT", path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cache::loadAnimationByName(const std::string& name) {
|
||||||
|
auto it = std::ranges::find_if(animations_, [&name](const auto& a) { return a.name == name; });
|
||||||
|
if (it == animations_.end()) { return; }
|
||||||
|
auto path = List::get()->get(name);
|
||||||
|
try {
|
||||||
|
auto bytes = Helper::loadFile(path);
|
||||||
|
if (bytes.empty()) { throw std::runtime_error("File is empty or could not be loaded"); }
|
||||||
|
it->yaml_data = bytes;
|
||||||
|
std::cout << "[lazy] Animation loaded: " << name << '\n';
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throwLoadError("ANIMATION", path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cache::loadRoomByName(const std::string& name) {
|
||||||
|
auto it = std::ranges::find_if(rooms_, [&name](const auto& r) { return r.name == name; });
|
||||||
|
if (it == rooms_.end()) { return; }
|
||||||
|
auto path = List::get()->get(name);
|
||||||
|
try {
|
||||||
|
it->room = std::make_shared<Room::Data>(Room::loadYAML(path));
|
||||||
|
std::cout << "[lazy] Room loaded: " << name << '\n';
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throwLoadError("ROOM", path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Resource
|
} // namespace Resource
|
||||||
|
|||||||
@@ -11,9 +11,14 @@ namespace Resource {
|
|||||||
|
|
||||||
class Cache {
|
class Cache {
|
||||||
public:
|
public:
|
||||||
static void init(); // Inicialización singleton
|
enum class LoadingMode {
|
||||||
static void destroy(); // Destrucción singleton
|
EAGER, // Carga todos los recursos en init() (comportamiento por defecto, producción)
|
||||||
static auto get() -> Cache*; // Acceso al singleton
|
LAZY // Sólo registra nombres; carga cada recurso la primera vez que se pide (desarrollo)
|
||||||
|
};
|
||||||
|
|
||||||
|
static void init(LoadingMode mode = LoadingMode::EAGER); // Inicialización singleton
|
||||||
|
static void destroy(); // Destrucción singleton
|
||||||
|
static auto get() -> Cache*; // Acceso al singleton
|
||||||
|
|
||||||
auto getSound(const std::string& name) -> JA_Sound_t*; // Getters de recursos
|
auto getSound(const std::string& name) -> JA_Sound_t*; // Getters de recursos
|
||||||
auto getMusic(const std::string& name) -> JA_Music_t*;
|
auto getMusic(const std::string& name) -> JA_Music_t*;
|
||||||
@@ -57,6 +62,18 @@ namespace Resource {
|
|||||||
void loadRooms();
|
void loadRooms();
|
||||||
void createText();
|
void createText();
|
||||||
|
|
||||||
|
// Registro de stubs (modo lazy): sólo nombres, sin contenido
|
||||||
|
void initLazyStubs();
|
||||||
|
|
||||||
|
// Cargadores bajo demanda (modo lazy): cargan un recurso individual por nombre
|
||||||
|
void loadSoundByName(const std::string& name);
|
||||||
|
void loadMusicByName(const std::string& name);
|
||||||
|
void loadSurfaceByName(const std::string& name);
|
||||||
|
void loadPaletteByName(const std::string& name);
|
||||||
|
void loadTextFileByName(const std::string& name);
|
||||||
|
void loadAnimationByName(const std::string& name);
|
||||||
|
void loadRoomByName(const std::string& name);
|
||||||
|
|
||||||
// Métodos de limpieza
|
// Métodos de limpieza
|
||||||
void clear();
|
void clear();
|
||||||
void clearSounds();
|
void clearSounds();
|
||||||
@@ -73,9 +90,11 @@ namespace Resource {
|
|||||||
[[noreturn]] static void throwLoadError(const std::string& asset_type, const std::string& file_path, const std::exception& e);
|
[[noreturn]] static void throwLoadError(const std::string& asset_type, const std::string& file_path, const std::exception& e);
|
||||||
|
|
||||||
// Constructor y destructor
|
// Constructor y destructor
|
||||||
Cache();
|
explicit Cache(LoadingMode mode);
|
||||||
~Cache() = default;
|
~Cache() = default;
|
||||||
|
|
||||||
|
LoadingMode loading_mode_ = LoadingMode::EAGER;
|
||||||
|
|
||||||
// Singleton instance
|
// Singleton instance
|
||||||
static Cache* cache;
|
static Cache* cache;
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,9 @@ struct SurfaceResource {
|
|||||||
|
|
||||||
// Estructura para almacenar objetos Palette y su nombre
|
// Estructura para almacenar objetos Palette y su nombre
|
||||||
struct ResourcePalette {
|
struct ResourcePalette {
|
||||||
std::string name; // Nombre de la surface
|
std::string name; // Nombre de la surface
|
||||||
Palette palette{}; // Paleta
|
Palette palette{}; // Paleta
|
||||||
|
bool loaded{false}; // Usado por el modo lazy para saber si ya se ha leído del disco
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para almacenar ficheros TextFile y su nombre
|
// Estructura para almacenar ficheros TextFile y su nombre
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ void Debug::loadFromFile() {
|
|||||||
spawn_settings_.spawn_y = Defaults::Game::Player::SPAWN_Y;
|
spawn_settings_.spawn_y = Defaults::Game::Player::SPAWN_Y;
|
||||||
spawn_settings_.flip = Defaults::Game::Player::SPAWN_FLIP;
|
spawn_settings_.flip = Defaults::Game::Player::SPAWN_FLIP;
|
||||||
initial_scene_ = SceneManager::Scene::GAME;
|
initial_scene_ = SceneManager::Scene::GAME;
|
||||||
|
lazy_loading_ = false;
|
||||||
|
|
||||||
std::ifstream file(debug_file_path_);
|
std::ifstream file(debug_file_path_);
|
||||||
if (!file.good()) {
|
if (!file.good()) {
|
||||||
@@ -162,6 +163,9 @@ void Debug::loadFromFile() {
|
|||||||
if (yaml.contains("initial_scene")) {
|
if (yaml.contains("initial_scene")) {
|
||||||
initial_scene_ = sceneFromString(yaml["initial_scene"].get_value<std::string>());
|
initial_scene_ = sceneFromString(yaml["initial_scene"].get_value<std::string>());
|
||||||
}
|
}
|
||||||
|
if (yaml.contains("lazy_loading")) {
|
||||||
|
lazy_loading_ = yaml["lazy_loading"].get_value<bool>();
|
||||||
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
// YAML inválido: resetear a defaults y sobreescribir
|
// YAML inválido: resetear a defaults y sobreescribir
|
||||||
spawn_settings_.room = Defaults::Game::Room::INITIAL;
|
spawn_settings_.room = Defaults::Game::Room::INITIAL;
|
||||||
@@ -169,6 +173,7 @@ void Debug::loadFromFile() {
|
|||||||
spawn_settings_.spawn_y = Defaults::Game::Player::SPAWN_Y;
|
spawn_settings_.spawn_y = Defaults::Game::Player::SPAWN_Y;
|
||||||
spawn_settings_.flip = Defaults::Game::Player::SPAWN_FLIP;
|
spawn_settings_.flip = Defaults::Game::Player::SPAWN_FLIP;
|
||||||
initial_scene_ = SceneManager::Scene::GAME;
|
initial_scene_ = SceneManager::Scene::GAME;
|
||||||
|
lazy_loading_ = false;
|
||||||
saveToFile();
|
saveToFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,6 +189,7 @@ void Debug::saveToFile() const {
|
|||||||
file << "spawn_y: " << (spawn_settings_.spawn_y / Tile::SIZE) << " # en tiles\n";
|
file << "spawn_y: " << (spawn_settings_.spawn_y / Tile::SIZE) << " # en tiles\n";
|
||||||
file << "spawn_flip: " << ((spawn_settings_.flip == Flip::RIGHT) ? "right" : "left") << "\n";
|
file << "spawn_flip: " << ((spawn_settings_.flip == Flip::RIGHT) ? "right" : "left") << "\n";
|
||||||
file << "initial_scene: " << sceneToString(initial_scene_) << "\n";
|
file << "initial_scene: " << sceneToString(initial_scene_) << "\n";
|
||||||
|
file << "lazy_loading: " << (lazy_loading_ ? "true" : "false") << " # carga perezosa de recursos (dev)\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
@@ -47,6 +47,7 @@ class Debug {
|
|||||||
void setSpawnSettings(const SpawnSettings& s) { spawn_settings_ = s; } // Establece los valores de spawn
|
void setSpawnSettings(const SpawnSettings& s) { spawn_settings_ = s; } // Establece los valores de spawn
|
||||||
[[nodiscard]] auto getInitialScene() const -> SceneManager::Scene { return initial_scene_; } // Obtiene la escena inicial de debug
|
[[nodiscard]] auto getInitialScene() const -> SceneManager::Scene { return initial_scene_; } // Obtiene la escena inicial de debug
|
||||||
void setInitialScene(SceneManager::Scene s) { initial_scene_ = s; } // Establece la escena inicial de debug
|
void setInitialScene(SceneManager::Scene s) { initial_scene_ = s; } // Establece la escena inicial de debug
|
||||||
|
[[nodiscard]] auto getLazyLoading() const -> bool { return lazy_loading_; } // Indica si el modo lazy de recursos está activo
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Debug* debug; // [SINGLETON] Objeto privado
|
static Debug* debug; // [SINGLETON] Objeto privado
|
||||||
@@ -64,6 +65,7 @@ class Debug {
|
|||||||
std::string debug_file_path_; // Ruta del archivo debug.yaml
|
std::string debug_file_path_; // Ruta del archivo debug.yaml
|
||||||
SpawnSettings spawn_settings_; // Configuración de spawn para debug
|
SpawnSettings spawn_settings_; // Configuración de spawn para debug
|
||||||
SceneManager::Scene initial_scene_ = SceneManager::Scene::GAME; // Escena inicial en debug
|
SceneManager::Scene initial_scene_ = SceneManager::Scene::GAME; // Escena inicial en debug
|
||||||
|
bool lazy_loading_ = false; // Carga lazy de recursos (dev)
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
@@ -160,8 +160,21 @@ Director::Director() {
|
|||||||
// Crea los objetos
|
// Crea los objetos
|
||||||
Screen::init();
|
Screen::init();
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
// En debug inicializamos Debug antes de Cache para leer el flag lazy_loading
|
||||||
|
Debug::init();
|
||||||
|
Debug::get()->setDebugFile(Resource::List::get()->get("debug.yaml"));
|
||||||
|
Debug::get()->loadFromFile();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Initialize resources (works for both release and development)
|
// Initialize resources (works for both release and development)
|
||||||
|
#ifdef _DEBUG
|
||||||
|
Resource::Cache::init(Debug::get()->getLazyLoading()
|
||||||
|
? Resource::Cache::LoadingMode::LAZY
|
||||||
|
: Resource::Cache::LoadingMode::EAGER);
|
||||||
|
#else
|
||||||
Resource::Cache::init();
|
Resource::Cache::init();
|
||||||
|
#endif
|
||||||
Notifier::init("", "8bithud");
|
Notifier::init("", "8bithud");
|
||||||
RenderInfo::init();
|
RenderInfo::init();
|
||||||
Console::init("8bithud");
|
Console::init("8bithud");
|
||||||
@@ -182,9 +195,6 @@ Director::Director() {
|
|||||||
Input::get()->applyGamepadBindingsFromOptions();
|
Input::get()->applyGamepadBindingsFromOptions();
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
Debug::init();
|
|
||||||
Debug::get()->setDebugFile(Resource::List::get()->get("debug.yaml"));
|
|
||||||
Debug::get()->loadFromFile();
|
|
||||||
SceneManager::current = Debug::get()->getInitialScene();
|
SceneManager::current = Debug::get()->getInitialScene();
|
||||||
MapEditor::init();
|
MapEditor::init();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1131,6 +1131,7 @@ auto MapEditor::setRoomProperty(const std::string& property, const std::string&
|
|||||||
std::string val = toLower(value);
|
std::string val = toLower(value);
|
||||||
|
|
||||||
if (property == "BGCOLOR") {
|
if (property == "BGCOLOR") {
|
||||||
|
val = colorToString(stringToColor(val)); // Normaliza a nombre canónico (acepta nombres e índices)
|
||||||
room_data_.bg_color = val;
|
room_data_.bg_color = val;
|
||||||
room_->setBgColor(val);
|
room_->setBgColor(val);
|
||||||
autosave();
|
autosave();
|
||||||
@@ -1138,6 +1139,7 @@ auto MapEditor::setRoomProperty(const std::string& property, const std::string&
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (property == "BORDER") {
|
if (property == "BORDER") {
|
||||||
|
val = colorToString(stringToColor(val));
|
||||||
room_data_.border_color = val;
|
room_data_.border_color = val;
|
||||||
Screen::get()->setBorderColor(stringToColor(val));
|
Screen::get()->setBorderColor(stringToColor(val));
|
||||||
autosave();
|
autosave();
|
||||||
@@ -1145,6 +1147,7 @@ auto MapEditor::setRoomProperty(const std::string& property, const std::string&
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (property == "ITEMCOLOR1") {
|
if (property == "ITEMCOLOR1") {
|
||||||
|
val = colorToString(stringToColor(val));
|
||||||
room_data_.item_color1 = val;
|
room_data_.item_color1 = val;
|
||||||
room_->setItemColors(room_data_.item_color1, room_data_.item_color2);
|
room_->setItemColors(room_data_.item_color1, room_data_.item_color2);
|
||||||
autosave();
|
autosave();
|
||||||
@@ -1152,6 +1155,7 @@ auto MapEditor::setRoomProperty(const std::string& property, const std::string&
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (property == "ITEMCOLOR2") {
|
if (property == "ITEMCOLOR2") {
|
||||||
|
val = colorToString(stringToColor(val));
|
||||||
room_data_.item_color2 = val;
|
room_data_.item_color2 = val;
|
||||||
room_->setItemColors(room_data_.item_color1, room_data_.item_color2);
|
room_->setItemColors(room_data_.item_color1, room_data_.item_color2);
|
||||||
autosave();
|
autosave();
|
||||||
|
|||||||
@@ -76,11 +76,8 @@ void Player::move(float delta_time) {
|
|||||||
case State::ON_SLOPE:
|
case State::ON_SLOPE:
|
||||||
moveOnSlope(delta_time);
|
moveOnSlope(delta_time);
|
||||||
break;
|
break;
|
||||||
case State::JUMPING:
|
case State::ON_AIR:
|
||||||
moveJumping(delta_time);
|
moveOnAir(delta_time);
|
||||||
break;
|
|
||||||
case State::FALLING:
|
|
||||||
moveFalling(delta_time);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
syncSpriteAndCollider(); // Actualiza la posición del sprite y las colisiones
|
syncSpriteAndCollider(); // Actualiza la posición del sprite y las colisiones
|
||||||
@@ -95,11 +92,8 @@ void Player::move(float delta_time) {
|
|||||||
case State::ON_SLOPE:
|
case State::ON_SLOPE:
|
||||||
Debug::get()->set("P.STATE", "ON_SLOPE");
|
Debug::get()->set("P.STATE", "ON_SLOPE");
|
||||||
break;
|
break;
|
||||||
case State::JUMPING:
|
case State::ON_AIR:
|
||||||
Debug::get()->set("P.STATE", "JUMPING");
|
Debug::get()->set("P.STATE", "ON_AIR");
|
||||||
break;
|
|
||||||
case State::FALLING:
|
|
||||||
Debug::get()->set("P.STATE", "FALLING");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -117,7 +111,8 @@ void Player::handleConveyorBelts() {
|
|||||||
|
|
||||||
void Player::handleShouldFall() {
|
void Player::handleShouldFall() {
|
||||||
if (!isOnFloor() and (state_ == State::ON_GROUND || state_ == State::ON_SLOPE)) {
|
if (!isOnFloor() and (state_ == State::ON_GROUND || state_ == State::ON_SLOPE)) {
|
||||||
transitionToState(State::FALLING);
|
vy_ = 0.0F;
|
||||||
|
transitionToState(State::ON_AIR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,37 +123,24 @@ void Player::transitionToState(State state) {
|
|||||||
switch (state) {
|
switch (state) {
|
||||||
case State::ON_GROUND:
|
case State::ON_GROUND:
|
||||||
vy_ = 0;
|
vy_ = 0;
|
||||||
handleDeathByFalling();
|
if (previous_state_ == State::ON_AIR) {
|
||||||
resetSoundControllersOnLanding();
|
Audio::get()->playSound(land_sound_, Audio::Group::GAME);
|
||||||
|
}
|
||||||
current_slope_ = nullptr;
|
current_slope_ = nullptr;
|
||||||
break;
|
break;
|
||||||
case State::ON_SLOPE:
|
case State::ON_SLOPE:
|
||||||
vy_ = 0;
|
vy_ = 0;
|
||||||
handleDeathByFalling();
|
if (previous_state_ == State::ON_AIR) {
|
||||||
resetSoundControllersOnLanding();
|
Audio::get()->playSound(land_sound_, Audio::Group::GAME);
|
||||||
|
}
|
||||||
updateCurrentSlope();
|
updateCurrentSlope();
|
||||||
if (current_slope_ == nullptr) {
|
if (current_slope_ == nullptr) {
|
||||||
// Los pies no coinciden con ninguna rampa: tratar como suelo plano
|
// Los pies no coinciden con ninguna rampa: tratar como suelo plano
|
||||||
state_ = State::ON_GROUND;
|
state_ = State::ON_GROUND;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case State::JUMPING:
|
case State::ON_AIR:
|
||||||
// Puede saltar desde ON_GROUND o ON_SLOPE
|
|
||||||
if (previous_state_ == State::ON_GROUND || previous_state_ == State::ON_SLOPE) {
|
|
||||||
vy_ = -MAX_VY;
|
|
||||||
last_grounded_position_ = y_;
|
|
||||||
updateVelocity();
|
|
||||||
jump_sound_ctrl_.start();
|
|
||||||
current_slope_ = nullptr;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case State::FALLING:
|
|
||||||
fall_start_position_ = static_cast<int>(y_);
|
|
||||||
last_grounded_position_ = static_cast<int>(y_);
|
last_grounded_position_ = static_cast<int>(y_);
|
||||||
vy_ = MAX_VY;
|
|
||||||
vx_ = 0.0F;
|
|
||||||
jump_sound_ctrl_.reset();
|
|
||||||
fall_sound_ctrl_.start(y_);
|
|
||||||
current_slope_ = nullptr;
|
current_slope_ = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -172,48 +154,48 @@ void Player::updateState(float delta_time) {
|
|||||||
case State::ON_SLOPE:
|
case State::ON_SLOPE:
|
||||||
updateOnSlope(delta_time);
|
updateOnSlope(delta_time);
|
||||||
break;
|
break;
|
||||||
case State::JUMPING:
|
case State::ON_AIR:
|
||||||
updateJumping(delta_time);
|
updateOnAir(delta_time);
|
||||||
break;
|
|
||||||
case State::FALLING:
|
|
||||||
updateFalling(delta_time);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inicia un salto desde ON_GROUND/ON_SLOPE: velocidad inicial hacia arriba + sonido + transición
|
||||||
|
void Player::startJump() {
|
||||||
|
vy_ = JUMP_VELOCITY;
|
||||||
|
last_grounded_position_ = y_;
|
||||||
|
Audio::get()->playSound(jump_sound_, Audio::Group::GAME);
|
||||||
|
transitionToState(State::ON_AIR);
|
||||||
|
}
|
||||||
|
|
||||||
// Actualización lógica del estado ON_GROUND
|
// Actualización lógica del estado ON_GROUND
|
||||||
void Player::updateOnGround(float delta_time) {
|
void Player::updateOnGround(float delta_time) {
|
||||||
(void)delta_time; // No usado en este método, pero se mantiene por consistencia
|
(void)delta_time; // No usado en este método, pero se mantiene por consistencia
|
||||||
handleConveyorBelts(); // Gestiona las cintas transportadoras
|
handleConveyorBelts(); // Gestiona las cintas transportadoras
|
||||||
handleShouldFall(); // Verifica si debe caer (no tiene suelo)
|
|
||||||
|
|
||||||
// Verifica si el jugador quiere saltar
|
// El salto tiene prioridad sobre la caída por falta de suelo
|
||||||
if (wanna_jump_) { transitionToState(State::JUMPING); }
|
if (wanna_jump_) {
|
||||||
|
startJump();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handleShouldFall(); // Verifica si debe caer (no tiene suelo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualización lógica del estado ON_SLOPE
|
// Actualización lógica del estado ON_SLOPE
|
||||||
void Player::updateOnSlope(float delta_time) {
|
void Player::updateOnSlope(float delta_time) {
|
||||||
(void)delta_time; // No usado en este método, pero se mantiene por consistencia
|
(void)delta_time; // No usado en este método, pero se mantiene por consistencia
|
||||||
|
|
||||||
|
if (wanna_jump_) {
|
||||||
|
startJump();
|
||||||
|
return;
|
||||||
|
}
|
||||||
handleShouldFall();
|
handleShouldFall();
|
||||||
// NOTA: No llamamos handleShouldFall() aquí porque moveOnSlope() ya maneja
|
|
||||||
// todas las condiciones de salida de la rampa (out of bounds, transición a superficie plana)
|
|
||||||
|
|
||||||
// Verifica si el jugador quiere saltar
|
|
||||||
if (wanna_jump_) { transitionToState(State::JUMPING); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualización lógica del estado JUMPING
|
// Actualización lógica del estado ON_AIR
|
||||||
void Player::updateJumping(float delta_time) {
|
void Player::updateOnAir(float delta_time) {
|
||||||
auto_movement_ = false; // Desactiva el movimiento automático durante el salto
|
(void)delta_time;
|
||||||
playJumpSound(delta_time); // Reproduce los sonidos de salto
|
auto_movement_ = false; // Desactiva el movimiento automático en el aire
|
||||||
handleJumpEnd(); // Verifica si el salto ha terminado (alcanzó la altura inicial)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actualización lógica del estado FALLING
|
|
||||||
void Player::updateFalling(float delta_time) {
|
|
||||||
auto_movement_ = false; // Desactiva el movimiento automático durante la caída
|
|
||||||
playFallSound(delta_time); // Reproduce los sonidos de caída
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Movimiento físico del estado ON_GROUND
|
// Movimiento físico del estado ON_GROUND
|
||||||
@@ -256,7 +238,8 @@ void Player::moveOnSlope(float delta_time) {
|
|||||||
// Verificar rampa válida antes de comprobar velocidad: si no hay rampa siempre caer,
|
// Verificar rampa válida antes de comprobar velocidad: si no hay rampa siempre caer,
|
||||||
// independientemente de si hay o no input (evita bloqueo con vx_=0 y slope null)
|
// independientemente de si hay o no input (evita bloqueo con vx_=0 y slope null)
|
||||||
if (current_slope_ == nullptr) {
|
if (current_slope_ == nullptr) {
|
||||||
transitionToState(State::FALLING);
|
vy_ = 0.0F;
|
||||||
|
transitionToState(State::ON_AIR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +303,8 @@ void Player::moveOnSlope(float delta_time) {
|
|||||||
transitionToState(State::ON_GROUND);
|
transitionToState(State::ON_GROUND);
|
||||||
} else {
|
} else {
|
||||||
// Sin soporte: empezar a caer
|
// Sin soporte: empezar a caer
|
||||||
transitionToState(State::FALLING);
|
vy_ = 0.0F;
|
||||||
|
transitionToState(State::ON_AIR);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -332,69 +316,39 @@ void Player::moveOnSlope(float delta_time) {
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Movimiento físico del estado JUMPING
|
// Movimiento físico del estado ON_AIR
|
||||||
void Player::moveJumping(float delta_time) {
|
// El jugador puede moverse horizontalmente en el aire y la gravedad siempre actúa.
|
||||||
// Movimiento horizontal
|
void Player::moveOnAir(float delta_time) {
|
||||||
|
// Movimiento horizontal libre según wanna_go_ (permite girar en el aire)
|
||||||
|
updateVelocity();
|
||||||
applyHorizontalMovement(delta_time);
|
applyHorizontalMovement(delta_time);
|
||||||
|
|
||||||
// Movimiento vertical
|
// Gravedad
|
||||||
applyGravity(delta_time);
|
applyGravity(delta_time);
|
||||||
|
|
||||||
const float DISPLACEMENT_Y = vy_ * delta_time;
|
const float DISPLACEMENT_Y = vy_ * delta_time;
|
||||||
// Movimiento vertical hacia arriba
|
|
||||||
|
// Subiendo: comprobar techo
|
||||||
if (vy_ < 0.0F) {
|
if (vy_ < 0.0F) {
|
||||||
const SDL_FRect PROJECTION = getProjection(Direction::UP, DISPLACEMENT_Y);
|
const SDL_FRect PROJECTION = getProjection(Direction::UP, DISPLACEMENT_Y);
|
||||||
|
|
||||||
// Comprueba la colisión
|
|
||||||
const int POS = room_->checkBottomSurfaces(PROJECTION);
|
const int POS = room_->checkBottomSurfaces(PROJECTION);
|
||||||
|
|
||||||
// Calcula la nueva posición
|
|
||||||
if (POS == Collision::NONE) {
|
if (POS == Collision::NONE) {
|
||||||
// Si no hay colisión
|
|
||||||
y_ += DISPLACEMENT_Y;
|
y_ += DISPLACEMENT_Y;
|
||||||
} else {
|
} else {
|
||||||
// Si hay colisión lo mueve hasta donde no colisiona -> FALLING
|
// Choque con techo: se pega por debajo y empieza a caer
|
||||||
y_ = POS + 1;
|
y_ = POS + 1;
|
||||||
transitionToState(State::FALLING);
|
vy_ = 0.0F;
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// Movimiento vertical hacia abajo
|
|
||||||
else if (vy_ > 0.0F) {
|
// Bajando: comprobar aterrizaje en superficies y rampas
|
||||||
// Crea el rectangulo de proyección en el eje Y para ver si colisiona
|
if (vy_ > 0.0F) {
|
||||||
const SDL_FRect PROJECTION = getProjection(Direction::DOWN, DISPLACEMENT_Y);
|
const SDL_FRect PROJECTION = getProjection(Direction::DOWN, DISPLACEMENT_Y);
|
||||||
|
handleLandingFromAir(DISPLACEMENT_Y, PROJECTION);
|
||||||
// JUMPING colisiona con rampas solo si vx_ == 0
|
|
||||||
if (vx_ == 0.0F) {
|
|
||||||
handleLandingFromAir(DISPLACEMENT_Y, PROJECTION);
|
|
||||||
} else {
|
|
||||||
// Comprueba la colisión con las superficies y las cintas transportadoras (sin rampas)
|
|
||||||
// Extendemos 1px hacia arriba para detectar suelos traversados ligeramente al
|
|
||||||
// entrar horizontalmente (consecuencia del margen h=HEIGHT-1 en la proyección horizontal)
|
|
||||||
const SDL_FRect ADJ = {.x = PROJECTION.x, .y = PROJECTION.y - 1.0F, .w = PROJECTION.w, .h = PROJECTION.h + 1.0F};
|
|
||||||
const float POS = std::max(room_->checkTopSurfaces(ADJ), room_->checkAutoSurfaces(ADJ));
|
|
||||||
if (POS != Collision::NONE) {
|
|
||||||
// Si hay colisión lo mueve hasta donde no colisiona y pasa a estar sobre la superficie
|
|
||||||
y_ = POS - HEIGHT;
|
|
||||||
transitionToState(State::ON_GROUND);
|
|
||||||
} else {
|
|
||||||
// Esta saltando con movimiento horizontal y no hay colisión con los muros
|
|
||||||
// Calcula la nueva posición (atraviesa rampas)
|
|
||||||
y_ += DISPLACEMENT_Y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Movimiento físico del estado FALLING
|
|
||||||
void Player::moveFalling(float delta_time) {
|
|
||||||
// Crea el rectangulo de proyección en el eje Y para ver si colisiona
|
|
||||||
const float DISPLACEMENT = vy_ * delta_time;
|
|
||||||
const SDL_FRect PROJECTION = getProjection(Direction::DOWN, DISPLACEMENT);
|
|
||||||
|
|
||||||
// Comprueba aterrizaje en superficies y rampas
|
|
||||||
handleLandingFromAir(DISPLACEMENT, PROJECTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comprueba si está situado en alguno de los cuatro bordes de la habitación
|
// Comprueba si está situado en alguno de los cuatro bordes de la habitación
|
||||||
auto Player::handleBorders() -> Room::Border {
|
auto Player::handleBorders() -> Room::Border {
|
||||||
if (x_ < PlayArea::LEFT) {
|
if (x_ < PlayArea::LEFT) {
|
||||||
@@ -410,10 +364,8 @@ auto Player::handleBorders() -> Room::Border {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (y_ + HEIGHT > PlayArea::BOTTOM) {
|
if (y_ + HEIGHT > PlayArea::BOTTOM) {
|
||||||
// Si llega en estado terminal, muere y no cruza
|
// Restricción de muerte por altura de caída desactivada
|
||||||
const bool SHOULD_DIE = static_cast<int>(y_) - last_grounded_position_ > MAX_FALLING_HEIGHT;
|
return Room::Border::BOTTOM;
|
||||||
if (SHOULD_DIE) { markAsDead(); }
|
|
||||||
return is_alive_ ? Room::Border::BOTTOM : Room::Border::NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Room::Border::NONE;
|
return Room::Border::NONE;
|
||||||
@@ -454,9 +406,8 @@ void Player::switchBorders() {
|
|||||||
|
|
||||||
// Aplica gravedad al jugador
|
// Aplica gravedad al jugador
|
||||||
void Player::applyGravity(float delta_time) {
|
void Player::applyGravity(float delta_time) {
|
||||||
// La gravedad solo se aplica cuando el jugador esta saltando
|
// La gravedad solo se aplica cuando el jugador esta en el aire
|
||||||
// Nunca mientras cae o esta de pie
|
if (state_ == State::ON_AIR) {
|
||||||
if (state_ == State::JUMPING) {
|
|
||||||
vy_ += GRAVITY_FORCE * delta_time;
|
vy_ += GRAVITY_FORCE * delta_time;
|
||||||
vy_ = std::min(vy_, MAX_VY);
|
vy_ = std::min(vy_, MAX_VY);
|
||||||
}
|
}
|
||||||
@@ -464,37 +415,13 @@ void Player::applyGravity(float delta_time) {
|
|||||||
|
|
||||||
// Establece la animación del jugador
|
// Establece la animación del jugador
|
||||||
void Player::animate(float delta_time) { // NOLINT(readability-make-member-function-const)
|
void Player::animate(float delta_time) { // NOLINT(readability-make-member-function-const)
|
||||||
if (vx_ != 0) {
|
if (state_ == State::ON_AIR) {
|
||||||
|
sprite_->setCurrentAnimation("jump");
|
||||||
|
} else if (vx_ != 0) {
|
||||||
|
sprite_->setCurrentAnimation("default");
|
||||||
sprite_->update(delta_time);
|
sprite_->update(delta_time);
|
||||||
}
|
} else {
|
||||||
}
|
sprite_->setCurrentAnimation("stand");
|
||||||
|
|
||||||
// Comprueba si ha finalizado el salto al alcanzar la altura de inicio
|
|
||||||
void Player::handleJumpEnd() {
|
|
||||||
// Si el jugador vuelve EXACTAMENTE a la altura inicial, debe CONTINUAR en JUMPING
|
|
||||||
// Solo cuando la SUPERA (desciende más allá) cambia a FALLING
|
|
||||||
if (state_ == State::JUMPING && vy_ > 0.0F && static_cast<int>(y_) > last_grounded_position_) {
|
|
||||||
transitionToState(State::FALLING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calcula y reproduce el sonido de salto basado en tiempo transcurrido
|
|
||||||
void Player::playJumpSound(float delta_time) { // NOLINT(readability-convert-member-functions-to-static)
|
|
||||||
size_t sound_index;
|
|
||||||
if (jump_sound_ctrl_.shouldPlay(delta_time, sound_index)) {
|
|
||||||
if (sound_index < jumping_sound_.size()) {
|
|
||||||
Audio::get()->playSound(jumping_sound_[sound_index], Audio::Group::GAME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calcula y reproduce el sonido de caída basado en distancia vertical recorrida
|
|
||||||
void Player::playFallSound(float delta_time) { // NOLINT(readability-convert-member-functions-to-static)
|
|
||||||
size_t sound_index;
|
|
||||||
if (fall_sound_ctrl_.shouldPlay(delta_time, y_, sound_index)) {
|
|
||||||
if (sound_index < falling_sound_.size()) {
|
|
||||||
Audio::get()->playSound(falling_sound_[sound_index], Audio::Group::GAME);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -665,98 +592,10 @@ void Player::updateFeet() {
|
|||||||
.y = y_ + HEIGHT};
|
.y = y_ + HEIGHT};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inicializa los sonidos de salto y caida
|
// Inicializa los sonidos de salto y aterrizaje
|
||||||
void Player::initSounds() { // NOLINT(readability-convert-member-functions-to-static)
|
void Player::initSounds() { // NOLINT(readability-convert-member-functions-to-static)
|
||||||
for (int i = 0; i < 24; ++i) {
|
jump_sound_ = Resource::Cache::get()->getSound("jump.wav");
|
||||||
std::string sound_file = "jump" + std::to_string(i + 1) + ".wav";
|
land_sound_ = Resource::Cache::get()->getSound("land.wav");
|
||||||
jumping_sound_[i] = Resource::Cache::get()->getSound(sound_file);
|
|
||||||
|
|
||||||
if (i >= 10) { // i+1 >= 11
|
|
||||||
falling_sound_[i - 10] = Resource::Cache::get()->getSound(sound_file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementación de JumpSoundController::start
|
|
||||||
void Player::JumpSoundController::start() {
|
|
||||||
current_index = 0;
|
|
||||||
elapsed_time = 0.0F;
|
|
||||||
active = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementación de JumpSoundController::reset
|
|
||||||
void Player::JumpSoundController::reset() {
|
|
||||||
active = false;
|
|
||||||
current_index = 0;
|
|
||||||
elapsed_time = 0.0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementación de JumpSoundController::shouldPlay
|
|
||||||
auto Player::JumpSoundController::shouldPlay(float delta_time, size_t& out_index) -> bool {
|
|
||||||
if (!active) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Acumula el tiempo transcurrido durante el salto
|
|
||||||
elapsed_time += delta_time;
|
|
||||||
|
|
||||||
// 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));
|
|
||||||
target_index = std::min(target_index, LAST_SOUND);
|
|
||||||
|
|
||||||
// Reproduce si hemos avanzado a un nuevo sonido
|
|
||||||
if (target_index > current_index) {
|
|
||||||
current_index = target_index;
|
|
||||||
out_index = current_index;
|
|
||||||
return true; // NOLINT(readability-simplify-boolean-expr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementación de FallSoundController::start
|
|
||||||
void Player::FallSoundController::start(float start_y) {
|
|
||||||
current_index = 0;
|
|
||||||
distance_traveled = 0.0F;
|
|
||||||
last_y = start_y;
|
|
||||||
active = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementación de FallSoundController::reset
|
|
||||||
void Player::FallSoundController::reset() {
|
|
||||||
active = false;
|
|
||||||
current_index = 0;
|
|
||||||
distance_traveled = 0.0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementación de FallSoundController::shouldPlay
|
|
||||||
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
|
|
||||||
|
|
||||||
if (!active) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Acumula la distancia recorrida (solo hacia abajo)
|
|
||||||
if (current_y > last_y) {
|
|
||||||
distance_traveled += (current_y - last_y);
|
|
||||||
}
|
|
||||||
last_y = current_y;
|
|
||||||
|
|
||||||
// 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));
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Reproduce si hemos avanzado a un nuevo índice (permite repetición de sonido 13)
|
|
||||||
if (target_index > current_index) {
|
|
||||||
current_index = target_index; // Guardamos el índice real (puede ser > LAST_SOUND)
|
|
||||||
out_index = sound_to_play; // Pero reproducimos LAST_SOUND cuando corresponde
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aplica los valores de spawn al jugador
|
// Aplica los valores de spawn al jugador
|
||||||
@@ -810,14 +649,6 @@ void Player::placeSprite() {
|
|||||||
sprite_->setPos(x_, y_);
|
sprite_->setPos(x_, y_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gestiona la muerta al ccaer desde muy alto
|
|
||||||
void Player::handleDeathByFalling() {
|
|
||||||
const int FALL_DISTANCE = static_cast<int>(y_) - last_grounded_position_;
|
|
||||||
if (previous_state_ == State::FALLING && FALL_DISTANCE > MAX_FALLING_HEIGHT) {
|
|
||||||
markAsDead(); // Muere si cae más de 32 píxeles
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calcula la velocidad en x
|
// Calcula la velocidad en x
|
||||||
void Player::updateVelocity() {
|
void Player::updateVelocity() {
|
||||||
if (auto_movement_) {
|
if (auto_movement_) {
|
||||||
@@ -900,12 +731,6 @@ auto Player::handleLandingFromAir(float displacement, const SDL_FRect& projectio
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resetea los controladores de sonido al aterrizar
|
|
||||||
void Player::resetSoundControllersOnLanding() {
|
|
||||||
jump_sound_ctrl_.reset();
|
|
||||||
fall_sound_ctrl_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Devuelve el rectangulo de proyeccion
|
// Devuelve el rectangulo de proyeccion
|
||||||
auto Player::getProjection(Direction direction, float displacement) -> SDL_FRect { // NOLINT(readability-convert-member-functions-to-static)
|
auto Player::getProjection(Direction direction, float displacement) -> SDL_FRect { // NOLINT(readability-convert-member-functions-to-static)
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ class Player {
|
|||||||
enum class State {
|
enum class State {
|
||||||
ON_GROUND, // En suelo plano o conveyor belt
|
ON_GROUND, // En suelo plano o conveyor belt
|
||||||
ON_SLOPE, // En rampa/pendiente
|
ON_SLOPE, // En rampa/pendiente
|
||||||
JUMPING,
|
ON_AIR, // En el aire (saltando, cayendo o caminando al vacío)
|
||||||
FALLING,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Direction {
|
enum class Direction {
|
||||||
@@ -34,10 +33,10 @@ class Player {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- Constantes de física (públicas para permitir cálculos en structs) ---
|
// --- Constantes de física (públicas para permitir cálculos en structs) ---
|
||||||
static constexpr float HORIZONTAL_VELOCITY = 40.0F; // Velocidad horizontal en pixels/segundo (0.6 * 66.67fps)
|
static constexpr float HORIZONTAL_VELOCITY = 60.0F; // Velocidad horizontal en pixels/segundo
|
||||||
static constexpr float MAX_VY = 80.0F; // Velocidad vertical máxima en pixels/segundo (1.2 * 66.67fps)
|
static constexpr float MAX_VY = 160.0F; // Velocidad vertical máxima en pixels/segundo
|
||||||
static constexpr float JUMP_VELOCITY = -80.0F; // Velocidad inicial del salto en pixels/segundo
|
static constexpr float JUMP_VELOCITY = -140.0F; // Velocidad inicial del salto en pixels/segundo
|
||||||
static constexpr float GRAVITY_FORCE = 155.6F; // Fuerza de gravedad en pixels/segundo² (0.035 * 66.67²)
|
static constexpr float GRAVITY_FORCE = 360.0F; // Fuerza de gravedad en pixels/segundo²
|
||||||
|
|
||||||
struct SpawnData {
|
struct SpawnData {
|
||||||
float x = 0;
|
float x = 0;
|
||||||
@@ -55,37 +54,6 @@ class Player {
|
|||||||
std::shared_ptr<Room> room = nullptr;
|
std::shared_ptr<Room> room = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JumpSoundController {
|
|
||||||
// Duración del salto calculada automáticamente con física: t = 2 * v0 / g
|
|
||||||
static constexpr float JUMP_DURATION = (2.0F * MAX_VY) / GRAVITY_FORCE;
|
|
||||||
static constexpr size_t FIRST_SOUND = 1; // Primer sonido a reproducir (índice 1)
|
|
||||||
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);
|
|
||||||
|
|
||||||
size_t current_index = 0; // Índice del sonido actual
|
|
||||||
float elapsed_time = 0.0F; // Tiempo transcurrido durante el salto
|
|
||||||
bool active = false; // Indica si el controlador está activo
|
|
||||||
|
|
||||||
void start(); // Inicia el controlador
|
|
||||||
void reset(); // Resetea el controlador
|
|
||||||
auto shouldPlay(float delta_time, size_t& out_index) -> bool; // Comprueba si debe reproducir un sonido
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FallSoundController {
|
|
||||||
static constexpr float PIXELS_PER_SOUND = 5.0F; // Intervalo de píxeles por sonido (configurable)
|
|
||||||
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)
|
|
||||||
|
|
||||||
size_t current_index = 0; // Índice del sonido actual
|
|
||||||
float distance_traveled = 0.0F; // Distancia acumulada durante la caída
|
|
||||||
float last_y = 0.0F; // Última posición Y registrada
|
|
||||||
bool active = false; // Indica si el controlador está activo
|
|
||||||
|
|
||||||
void start(float start_y); // Inicia el controlador
|
|
||||||
void reset(); // Resetea el controlador
|
|
||||||
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 ---
|
||||||
explicit Player(const Data& player);
|
explicit Player(const Data& player);
|
||||||
~Player() = default;
|
~Player() = default;
|
||||||
@@ -155,12 +123,9 @@ class Player {
|
|||||||
int last_grounded_position_ = 0; // Ultima posición en Y en la que se estaba en contacto con el suelo (hace doble función: tracking de caída + altura inicial del salto)
|
int last_grounded_position_ = 0; // Ultima posición en Y en la que se estaba en contacto con el suelo (hace doble función: tracking de caída + altura inicial del salto)
|
||||||
|
|
||||||
// --- Variables de renderizado y sonido ---
|
// --- Variables de renderizado y sonido ---
|
||||||
Uint8 color_ = 0; // Color del jugador
|
Uint8 color_ = 0; // Color del jugador
|
||||||
std::array<JA_Sound_t*, 24> jumping_sound_{}; // Array con todos los sonidos del salto
|
JA_Sound_t* jump_sound_ = nullptr; // Sonido al iniciar el salto
|
||||||
std::array<JA_Sound_t*, 14> falling_sound_{}; // Array con todos los sonidos de la caída
|
JA_Sound_t* land_sound_ = nullptr; // Sonido al aterrizar en el suelo
|
||||||
JumpSoundController jump_sound_ctrl_; // Controlador de sonidos de salto
|
|
||||||
FallSoundController fall_sound_ctrl_; // Controlador de sonidos de caída
|
|
||||||
int fall_start_position_ = 0; // Posición Y al iniciar la caída
|
|
||||||
|
|
||||||
void handleConveyorBelts();
|
void handleConveyorBelts();
|
||||||
void handleShouldFall();
|
void handleShouldFall();
|
||||||
@@ -169,14 +134,12 @@ class Player {
|
|||||||
// --- Métodos de actualización por estado ---
|
// --- Métodos de actualización por estado ---
|
||||||
void updateOnGround(float delta_time); // Actualización lógica estado ON_GROUND
|
void updateOnGround(float delta_time); // Actualización lógica estado ON_GROUND
|
||||||
void updateOnSlope(float delta_time); // Actualización lógica estado ON_SLOPE
|
void updateOnSlope(float delta_time); // Actualización lógica estado ON_SLOPE
|
||||||
void updateJumping(float delta_time); // Actualización lógica estado JUMPING
|
void updateOnAir(float delta_time); // Actualización lógica estado ON_AIR
|
||||||
void updateFalling(float delta_time); // Actualización lógica estado FALLING
|
|
||||||
|
|
||||||
// --- Métodos de movimiento por estado ---
|
// --- Métodos de movimiento por estado ---
|
||||||
void moveOnGround(float delta_time); // Movimiento físico estado ON_GROUND
|
void moveOnGround(float delta_time); // Movimiento físico estado ON_GROUND
|
||||||
void moveOnSlope(float delta_time); // Movimiento físico estado ON_SLOPE
|
void moveOnSlope(float delta_time); // Movimiento físico estado ON_SLOPE
|
||||||
void moveJumping(float delta_time); // Movimiento físico estado JUMPING
|
void moveOnAir(float delta_time); // Movimiento físico estado ON_AIR
|
||||||
void moveFalling(float delta_time); // Movimiento físico estado FALLING
|
|
||||||
|
|
||||||
// --- Funciones de inicialización ---
|
// --- Funciones de inicialización ---
|
||||||
void initSprite(const std::string& animations_path); // Inicializa el sprite del jugador
|
void initSprite(const std::string& animations_path); // Inicializa el sprite del jugador
|
||||||
@@ -188,6 +151,7 @@ class Player {
|
|||||||
|
|
||||||
// --- Funciones de gestión de estado ---
|
// --- Funciones de gestión de estado ---
|
||||||
void transitionToState(State state); // Cambia el estado del jugador
|
void transitionToState(State state); // Cambia el estado del jugador
|
||||||
|
void startJump(); // Inicia el salto: velocidad inicial + sonido + transición a ON_AIR
|
||||||
|
|
||||||
// --- Funciones de física ---
|
// --- Funciones de física ---
|
||||||
void applyGravity(float delta_time); // Aplica gravedad al jugador
|
void applyGravity(float delta_time); // Aplica gravedad al jugador
|
||||||
@@ -197,7 +161,6 @@ class Player {
|
|||||||
auto getProjection(Direction direction, float displacement) -> SDL_FRect; // Devuelve el rectangulo de proyeccion
|
auto getProjection(Direction direction, float displacement) -> SDL_FRect; // Devuelve el rectangulo de proyeccion
|
||||||
void applyHorizontalMovement(float delta_time); // Aplica movimiento horizontal con colisión de muros
|
void applyHorizontalMovement(float delta_time); // Aplica movimiento horizontal con colisión de muros
|
||||||
auto handleLandingFromAir(float displacement, const SDL_FRect& projection) -> bool; // Detecta aterrizaje en superficies y rampas
|
auto handleLandingFromAir(float displacement, const SDL_FRect& projection) -> bool; // Detecta aterrizaje en superficies y rampas
|
||||||
void resetSoundControllersOnLanding(); // Resetea los controladores de sonido al aterrizar
|
|
||||||
|
|
||||||
// --- Funciones de detección de superficies ---
|
// --- Funciones de detección de superficies ---
|
||||||
auto isOnFloor() -> bool; // Comprueba si el jugador tiene suelo debajo de los pies
|
auto isOnFloor() -> bool; // Comprueba si el jugador tiene suelo debajo de los pies
|
||||||
@@ -216,11 +179,7 @@ class Player {
|
|||||||
// --- Funciones de finalización ---
|
// --- Funciones de finalización ---
|
||||||
void animate(float delta_time); // Establece la animación del jugador
|
void animate(float delta_time); // Establece la animación del jugador
|
||||||
auto handleBorders() -> Room::Border; // Comprueba si se halla en alguno de los cuatro bordes
|
auto handleBorders() -> Room::Border; // Comprueba si se halla en alguno de los cuatro bordes
|
||||||
void handleJumpEnd(); // Comprueba si ha finalizado el salto al alcanzar la altura de inicio
|
|
||||||
auto handleKillingTiles() -> bool; // Comprueba que el jugador no toque ningun tile de los que matan
|
auto handleKillingTiles() -> bool; // Comprueba que el jugador no toque ningun tile de los que matan
|
||||||
void playJumpSound(float delta_time); // Calcula y reproduce el sonido de salto
|
|
||||||
void playFallSound(float delta_time); // Calcula y reproduce el sonido de caer
|
|
||||||
void handleDeathByFalling(); // Gestiona la muerte al caer desde muy alto
|
|
||||||
void updateVelocity(); // Calcula la velocidad en x
|
void updateVelocity(); // Calcula la velocidad en x
|
||||||
void markAsDead(); // Marca al jugador como muerto
|
void markAsDead(); // Marca al jugador como muerto
|
||||||
};
|
};
|
||||||
@@ -21,6 +21,13 @@ auto RoomLoader::convertRoomConnection(const std::string& value) -> std::string
|
|||||||
return value + ".yaml";
|
return value + ".yaml";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lee un nodo de color tolerando tanto string ("red", "bright_blue") como entero (índice de paleta)
|
||||||
|
static auto readColorNode(const fkyaml::node& node) -> std::string {
|
||||||
|
if (node.is_string()) { return node.get_value<std::string>(); }
|
||||||
|
if (node.is_integer()) { return std::to_string(node.get_value<int>()); }
|
||||||
|
return "black";
|
||||||
|
}
|
||||||
|
|
||||||
// Convierte string de autoSurface a int
|
// Convierte string de autoSurface a int
|
||||||
auto RoomLoader::convertAutoSurface(const fkyaml::node& node) -> int { // NOLINT(readability-convert-member-functions-to-static)
|
auto RoomLoader::convertAutoSurface(const fkyaml::node& node) -> int { // NOLINT(readability-convert-member-functions-to-static)
|
||||||
if (node.is_integer()) {
|
if (node.is_integer()) {
|
||||||
@@ -71,10 +78,10 @@ void RoomLoader::parseRoomConfig(const fkyaml::node& yaml, Room::Data& room, con
|
|||||||
room.name = room_node["name"].get_value<std::string>();
|
room.name = room_node["name"].get_value<std::string>();
|
||||||
}
|
}
|
||||||
if (room_node.contains("bgColor")) {
|
if (room_node.contains("bgColor")) {
|
||||||
room.bg_color = room_node["bgColor"].get_value<std::string>();
|
room.bg_color = readColorNode(room_node["bgColor"]);
|
||||||
}
|
}
|
||||||
if (room_node.contains("border")) {
|
if (room_node.contains("border")) {
|
||||||
room.border_color = room_node["border"].get_value<std::string>();
|
room.border_color = readColorNode(room_node["border"]);
|
||||||
}
|
}
|
||||||
if (room_node.contains("tileSetFile")) {
|
if (room_node.contains("tileSetFile")) {
|
||||||
room.tile_set_file = room_node["tileSetFile"].get_value<std::string>();
|
room.tile_set_file = room_node["tileSetFile"].get_value<std::string>();
|
||||||
@@ -87,11 +94,11 @@ void RoomLoader::parseRoomConfig(const fkyaml::node& yaml, Room::Data& room, con
|
|||||||
|
|
||||||
// Item colors
|
// Item colors
|
||||||
room.item_color1 = room_node.contains("itemColor1")
|
room.item_color1 = room_node.contains("itemColor1")
|
||||||
? room_node["itemColor1"].get_value_or<std::string>("yellow")
|
? readColorNode(room_node["itemColor1"])
|
||||||
: "yellow";
|
: "yellow";
|
||||||
|
|
||||||
room.item_color2 = room_node.contains("itemColor2")
|
room.item_color2 = room_node.contains("itemColor2")
|
||||||
? room_node["itemColor2"].get_value_or<std::string>("magenta")
|
? readColorNode(room_node["itemColor2"])
|
||||||
: "magenta";
|
: "magenta";
|
||||||
|
|
||||||
// Dirección de la cinta transportadora (left/none/right)
|
// Dirección de la cinta transportadora (left/none/right)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ Credits::Credits()
|
|||||||
|
|
||||||
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK)); // Cambia el color del borde
|
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK)); // Cambia el color del borde
|
||||||
fillTexture(); // Escribe el texto en la textura
|
fillTexture(); // Escribe el texto en la textura
|
||||||
Audio::get()->playMusic("574071_EA_DTV.ogg"); // Inicia la musica
|
Audio::get()->playMusic("574071_EA_DTV.ogg"); // Inicia la musica
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comprueba el manejador de eventos
|
// Comprueba el manejador de eventos
|
||||||
|
|||||||
@@ -35,12 +35,12 @@ class GameOver {
|
|||||||
static constexpr float ENDING_DURATION = 1.12F; // Espera en negro antes de salir
|
static constexpr float ENDING_DURATION = 1.12F; // Espera en negro antes de salir
|
||||||
|
|
||||||
// --- Constantes de posición ---
|
// --- Constantes de posición ---
|
||||||
static constexpr int TEXT_Y = 32; // Posición Y del texto principal
|
static constexpr int TEXT_Y = 32; // Posición Y del texto principal
|
||||||
static constexpr int SPRITE_Y_OFFSET = 30; // Offset Y para sprites desde TEXT_Y
|
static constexpr int SPRITE_Y_OFFSET = 30; // Offset Y para sprites desde TEXT_Y
|
||||||
static constexpr int PLAYER_X_OFFSET = 10; // Offset X del jugador desde el centro
|
static constexpr int PLAYER_X_OFFSET = 10; // Offset X del jugador desde el centro
|
||||||
static constexpr int TV_X_OFFSET = 10; // Offset X del TV desde el centro
|
static constexpr int TV_X_OFFSET = 10; // Offset X del TV desde el centro
|
||||||
static constexpr int ITEMS_Y_OFFSET = 80; // Offset Y del texto de items desde TEXT_Y
|
static constexpr int ITEMS_Y_OFFSET = 80; // Offset Y del texto de items desde TEXT_Y
|
||||||
static constexpr int ROOMS_Y_OFFSET = 90; // Offset Y del texto de rooms desde TEXT_Y
|
static constexpr int ROOMS_Y_OFFSET = 90; // Offset Y del texto de rooms desde TEXT_Y
|
||||||
|
|
||||||
// --- Métodos ---
|
// --- Métodos ---
|
||||||
void update(); // Actualiza el objeto
|
void update(); // Actualiza el objeto
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ Title::Title()
|
|||||||
initMarquee(); // Inicializa la marquesina
|
initMarquee(); // Inicializa la marquesina
|
||||||
createCheevosTexture(); // Crea y rellena la textura para mostrar los logros
|
createCheevosTexture(); // Crea y rellena la textura para mostrar los logros
|
||||||
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK)); // Cambia el color del borde
|
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK)); // Cambia el color del borde
|
||||||
Audio::get()->playMusic("574071_EA_DTV.ogg"); // Inicia la musica
|
Audio::get()->playMusic("574071_EA_DTV.ogg"); // Inicia la musica
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
|
|||||||
@@ -17,75 +17,75 @@
|
|||||||
* de 3 niveles de intensidad (0, 128, 255) para cada componente RGB.
|
* de 3 niveles de intensidad (0, 128, 255) para cada componente RGB.
|
||||||
*/
|
*/
|
||||||
class Color {
|
class Color {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @enum Cpc
|
* @enum Cpc
|
||||||
* @brief Índices de los colores de la paleta Amstrad CPC
|
* @brief Índices de los colores de la paleta Amstrad CPC
|
||||||
*
|
*
|
||||||
* Los nombres corresponden a los colores oficiales documentados por Amstrad.
|
* Los nombres corresponden a los colores oficiales documentados por Amstrad.
|
||||||
* El índice 0 está reservado para transparencia.
|
* El índice 0 está reservado para transparencia.
|
||||||
*/
|
*/
|
||||||
enum class Cpc : Uint8 {
|
enum class Cpc : Uint8 {
|
||||||
// Transparente (índice 0)
|
// Transparente (índice 0)
|
||||||
CLEAR = 0, // Nota: No usar "TRANSPARENT" - colisiona con macro de Windows
|
CLEAR = 0, // Nota: No usar "TRANSPARENT" - colisiona con macro de Windows
|
||||||
|
|
||||||
// Negros y azules (R=0)
|
// Negros y azules (R=0)
|
||||||
BLACK = 1, // 0, 0, 0
|
BLACK = 1, // 0, 0, 0
|
||||||
BLUE = 2, // 0, 0, 128
|
BLUE = 2, // 0, 0, 128
|
||||||
BRIGHT_BLUE = 3, // 0, 0, 255
|
BRIGHT_BLUE = 3, // 0, 0, 255
|
||||||
|
|
||||||
// Rojos y magentas (G=0)
|
// Rojos y magentas (G=0)
|
||||||
RED = 4, // 128, 0, 0
|
RED = 4, // 128, 0, 0
|
||||||
MAGENTA = 5, // 128, 0, 128
|
MAGENTA = 5, // 128, 0, 128
|
||||||
MAUVE = 6, // 128, 0, 255
|
MAUVE = 6, // 128, 0, 255
|
||||||
BRIGHT_RED = 7, // 255, 0, 0
|
BRIGHT_RED = 7, // 255, 0, 0
|
||||||
PURPLE = 8, // 255, 0, 128
|
PURPLE = 8, // 255, 0, 128
|
||||||
BRIGHT_MAGENTA = 9, // 255, 0, 255
|
BRIGHT_MAGENTA = 9, // 255, 0, 255
|
||||||
|
|
||||||
// Verdes y cianes (R=0, G>0)
|
// Verdes y cianes (R=0, G>0)
|
||||||
GREEN = 10, // 0, 128, 0
|
GREEN = 10, // 0, 128, 0
|
||||||
CYAN = 11, // 0, 128, 128
|
CYAN = 11, // 0, 128, 128
|
||||||
SKY_BLUE = 12, // 0, 128, 255
|
SKY_BLUE = 12, // 0, 128, 255
|
||||||
|
|
||||||
// Amarillos y blancos medios (G=128)
|
// Amarillos y blancos medios (G=128)
|
||||||
YELLOW = 13, // 128, 128, 0
|
YELLOW = 13, // 128, 128, 0
|
||||||
WHITE = 14, // 128, 128, 128
|
WHITE = 14, // 128, 128, 128
|
||||||
PASTEL_BLUE = 15, // 128, 128, 255
|
PASTEL_BLUE = 15, // 128, 128, 255
|
||||||
|
|
||||||
// Naranjas y rosas (R=255, G=128)
|
// Naranjas y rosas (R=255, G=128)
|
||||||
ORANGE = 16, // 255, 128, 0
|
ORANGE = 16, // 255, 128, 0
|
||||||
PINK = 17, // 255, 128, 128
|
PINK = 17, // 255, 128, 128
|
||||||
PASTEL_MAGENTA = 18, // 255, 128, 255
|
PASTEL_MAGENTA = 18, // 255, 128, 255
|
||||||
|
|
||||||
// Verdes brillantes (G=255)
|
// Verdes brillantes (G=255)
|
||||||
BRIGHT_GREEN = 19, // 0, 255, 0
|
BRIGHT_GREEN = 19, // 0, 255, 0
|
||||||
SEA_GREEN = 20, // 0, 255, 128
|
SEA_GREEN = 20, // 0, 255, 128
|
||||||
BRIGHT_CYAN = 21, // 0, 255, 255
|
BRIGHT_CYAN = 21, // 0, 255, 255
|
||||||
|
|
||||||
// Limas y pasteles verdes (G=255)
|
// Limas y pasteles verdes (G=255)
|
||||||
LIME = 22, // 128, 255, 0
|
LIME = 22, // 128, 255, 0
|
||||||
PASTEL_GREEN = 23, // 128, 255, 128
|
PASTEL_GREEN = 23, // 128, 255, 128
|
||||||
PASTEL_CYAN = 24, // 128, 255, 255
|
PASTEL_CYAN = 24, // 128, 255, 255
|
||||||
|
|
||||||
// Amarillos brillantes y blancos (R=255, G=255)
|
// Amarillos brillantes y blancos (R=255, G=255)
|
||||||
BRIGHT_YELLOW = 25, // 255, 255, 0
|
BRIGHT_YELLOW = 25, // 255, 255, 0
|
||||||
PASTEL_YELLOW = 26, // 255, 255, 128
|
PASTEL_YELLOW = 26, // 255, 255, 128
|
||||||
BRIGHT_WHITE = 27 // 255, 255, 255
|
BRIGHT_WHITE = 27 // 255, 255, 255
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Obtiene el índice de paleta de un color CPC
|
* @brief Obtiene el índice de paleta de un color CPC
|
||||||
* @param color Color del enum Cpc
|
* @param color Color del enum Cpc
|
||||||
* @return Índice de paleta (Uint8)
|
* @return Índice de paleta (Uint8)
|
||||||
*/
|
*/
|
||||||
static constexpr auto index(Cpc color) -> Uint8 {
|
static constexpr auto index(Cpc color) -> Uint8 {
|
||||||
return static_cast<Uint8>(color);
|
return static_cast<Uint8>(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convierte un nombre de color (string) a índice de paleta
|
* @brief Convierte un nombre de color (string) a índice de paleta
|
||||||
* @param name Nombre del color en minúsculas (ej: "cyan", "bright_blue")
|
* @param name Nombre del color en minúsculas (ej: "cyan", "bright_blue")
|
||||||
* @return Índice de paleta, o 1 (BLACK) si no se encuentra
|
* @return Índice de paleta, o 1 (BLACK) si no se encuentra
|
||||||
*/
|
*/
|
||||||
static auto fromString(const std::string& name) -> Uint8;
|
static auto fromString(const std::string& name) -> Uint8;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
namespace Texts {
|
namespace Texts {
|
||||||
constexpr const char* WINDOW_CAPTION = "© 2026 Projecte 2026 — JailDesigner";
|
constexpr const char* WINDOW_CAPTION = "© 2026 Projecte 2026 — JailDesigner";
|
||||||
constexpr const char* COPYRIGHT = "@2026 JailDesigner";
|
constexpr const char* COPYRIGHT = "@2026 JailDesigner";
|
||||||
constexpr const char* VERSION = "1.13"; // Versión por defecto
|
constexpr const char* VERSION = "0.1"; // Versión por defecto
|
||||||
} // namespace Texts
|
} // namespace Texts
|
||||||
|
|
||||||
// Tamaño de bloque
|
// Tamaño de bloque
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#include "utils/utils.hpp"
|
#include "utils/utils.hpp"
|
||||||
|
|
||||||
#include <algorithm> // Para find, transform
|
#include <algorithm> // Para find, transform, ranges::all_of
|
||||||
#include <cctype> // Para tolower
|
#include <array> // Para array
|
||||||
|
#include <cctype> // Para tolower, isdigit
|
||||||
#include <cmath> // Para round, abs
|
#include <cmath> // Para round, abs
|
||||||
#include <cstdlib> // Para abs
|
#include <cstdlib> // Para abs
|
||||||
#include <exception> // Para exception
|
#include <exception> // Para exception
|
||||||
@@ -366,10 +367,36 @@ auto stringToColor(const std::string& str) -> Uint8 {
|
|||||||
auto it = PALETTE_MAP.find(str);
|
auto it = PALETTE_MAP.find(str);
|
||||||
if (it != PALETTE_MAP.end()) {
|
if (it != PALETTE_MAP.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
} // Si no se encuentra el color, devolvemos negro por defecto
|
}
|
||||||
|
|
||||||
|
// Fallback: si el string es numérico (p.ej. "4"), lo tratamos como índice de paleta
|
||||||
|
if (!str.empty() && std::ranges::all_of(str, [](char c) { return std::isdigit(static_cast<unsigned char>(c)) != 0; })) {
|
||||||
|
const int IDX = safeStoi(str, 0);
|
||||||
|
if (IDX >= 0 && IDX <= 255) {
|
||||||
|
return static_cast<Uint8>(IDX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si no se encuentra el color, devolvemos negro por defecto
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inverso de stringToColor: devuelve el nombre canónico para un índice de paleta (o el propio número si no hay)
|
||||||
|
auto colorToString(Uint8 index) -> std::string {
|
||||||
|
static const std::array<const char*, 16> NAMES = {
|
||||||
|
"black", "bright_black",
|
||||||
|
"blue", "bright_blue",
|
||||||
|
"red", "bright_red",
|
||||||
|
"magenta", "bright_magenta",
|
||||||
|
"green", "bright_green",
|
||||||
|
"cyan", "bright_cyan",
|
||||||
|
"yellow", "bright_yellow",
|
||||||
|
"white", "bright_white"};
|
||||||
|
if (index < NAMES.size()) { return NAMES[index]; }
|
||||||
|
if (index == 255) { return "transparent"; }
|
||||||
|
return std::to_string(index);
|
||||||
|
}
|
||||||
|
|
||||||
// Convierte una cadena a un entero de forma segura
|
// Convierte una cadena a un entero de forma segura
|
||||||
auto safeStoi(const std::string& value, int default_value) -> int {
|
auto safeStoi(const std::string& value, int default_value) -> int {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -92,7 +92,8 @@ auto toSDLRect(const SDL_FRect& frect) -> SDL_Rect; // Convierte SDL_FRect
|
|||||||
auto toSDLPoint(const SDL_FPoint& fpoint) -> SDL_Point; // Convierte SDL_FPoint a SDL_Point
|
auto toSDLPoint(const SDL_FPoint& fpoint) -> SDL_Point; // Convierte SDL_FPoint a SDL_Point
|
||||||
|
|
||||||
// CONVERSIONES DE STRING
|
// CONVERSIONES DE STRING
|
||||||
auto stringToColor(const std::string& str) -> Uint8; // String a índice de paleta
|
auto stringToColor(const std::string& str) -> Uint8; // String a índice de paleta (acepta nombres o números)
|
||||||
|
auto colorToString(Uint8 index) -> std::string; // Índice de paleta a nombre canónico
|
||||||
auto safeStoi(const std::string& value, int default_value = 0) -> int; // String a int seguro (sin excepciones)
|
auto safeStoi(const std::string& value, int default_value = 0) -> int; // String a int seguro (sin excepciones)
|
||||||
auto stringToBool(const std::string& str) -> bool; // String a bool (true/1/yes/on)
|
auto stringToBool(const std::string& str) -> bool; // String a bool (true/1/yes/on)
|
||||||
auto boolToString(bool value) -> std::string; // Bool a string (1/0)
|
auto boolToString(bool value) -> std::string; // Bool a string (1/0)
|
||||||
|
|||||||
Reference in New Issue
Block a user