diff --git a/source/core/rendering/pixel_reveal.cpp b/source/core/rendering/pixel_reveal.cpp index 36275e9d..41e3c3a8 100644 --- a/source/core/rendering/pixel_reveal.cpp +++ b/source/core/rendering/pixel_reveal.cpp @@ -2,13 +2,14 @@ #include // Para min #include // Para iota +#include // Para queue (BFS en modo ORDERED) #include // Para mt19937, shuffle #include "core/rendering/surface.hpp" // Para Surface #include "utils/utils.hpp" // Para PaletteColor // Constructor -PixelReveal::PixelReveal(int width, int height, float pixels_per_second, float step_duration, int num_steps) +PixelReveal::PixelReveal(int width, int height, float pixels_per_second, float step_duration, int num_steps, bool reverse, RevealMode mode) : cover_surface_(std::make_shared(width, height)), reveal_order_(height), row_step_(height, 0), @@ -16,16 +17,51 @@ PixelReveal::PixelReveal(int width, int height, float pixels_per_second, float s height_(height), pixels_per_second_(pixels_per_second), step_duration_(step_duration), - num_steps_(num_steps) { - // Rellena la máscara con negro sólido - cover_surface_->clear(static_cast(PaletteColor::BLACK)); + num_steps_(num_steps), + reverse_(reverse), + mode_(mode) { + // En modo normal: empieza negro sólido (se irá revelando a transparente) + // En modo inverso: empieza transparente (se irá cubriendo de negro) + const auto INITIAL_COLOR = reverse_ ? static_cast(PaletteColor::TRANSPARENT) : static_cast(PaletteColor::BLACK); + cover_surface_->clear(INITIAL_COLOR); - // Genera el orden aleatorio de columnas por fila usando la fila como semilla (reproducible) - for (int r = 0; r < height_; r++) { - reveal_order_[r].resize(width_); - std::iota(reveal_order_[r].begin(), reveal_order_[r].end(), 0); - std::mt19937 rng(static_cast(r)); - std::shuffle(reveal_order_[r].begin(), reveal_order_[r].end(), rng); + if (mode_ == RevealMode::ORDERED) { + // Calcula offsets por bisección BFS: 0, N/2, N/4, 3N/4, ... + std::vector offsets; + offsets.push_back(0); + std::queue> bq; + bq.push({0, num_steps_}); + while (static_cast(offsets.size()) < num_steps_) { + auto [lo, hi] = bq.front(); + bq.pop(); + if (hi - lo <= 1) { + continue; + } + const int MID = (lo + hi) / 2; + offsets.push_back(MID); + bq.push({lo, MID}); + bq.push({MID, hi}); + } + // Genera el orden: para cada offset, todas las columnas col = offset, offset+N, offset+2N, ... + std::vector ordered_cols; + ordered_cols.reserve(width_); + for (const int off : offsets) { + for (int col = off; col < width_; col += num_steps_) { + ordered_cols.push_back(col); + } + } + // Todas las filas usan el mismo orden (sin aleatoriedad) + for (int r = 0; r < height_; r++) { + reveal_order_[r] = ordered_cols; + } + } else { + // Modo RANDOM: orden aleatorio por fila usando la fila como semilla (reproducible) + for (int r = 0; r < height_; r++) { + reveal_order_[r].resize(width_); + std::iota(reveal_order_[r].begin(), reveal_order_[r].end(), 0); + std::mt19937 rng(static_cast(r)); + std::shuffle(reveal_order_[r].begin(), reveal_order_[r].end(), rng); + } } } @@ -34,7 +70,8 @@ PixelReveal::~PixelReveal() = default; // Actualiza el estado del revelado void PixelReveal::update(float time_active) { - const auto TRANSPARENT = static_cast(PaletteColor::TRANSPARENT); + // En modo normal revela (pone transparente); en modo inverso cubre (pone negro) + const auto PIXEL_COLOR = reverse_ ? static_cast(PaletteColor::BLACK) : static_cast(PaletteColor::TRANSPARENT); for (int r = 0; r < height_; r++) { const float T_START = static_cast(r) / pixels_per_second_; @@ -47,14 +84,14 @@ void PixelReveal::update(float time_active) { const int STEPS = std::min(num_steps_, static_cast(TIME_IN_ROW / step_duration_)); if (STEPS > row_step_[r]) { - // Revela los píxeles de los pasos pendientes + // Procesa los píxeles de los pasos pendientes for (int step = row_step_[r]; step < STEPS; step++) { const int START_IDX = step * width_ / num_steps_; const int END_IDX = (step == num_steps_ - 1) ? width_ : (step + 1) * width_ / num_steps_; for (int idx = START_IDX; idx < END_IDX; idx++) { const int COL = reveal_order_[r][idx]; - cover_surface_->putPixel(COL, r, TRANSPARENT); + cover_surface_->putPixel(COL, r, PIXEL_COLOR); } } row_step_[r] = STEPS; diff --git a/source/core/rendering/pixel_reveal.hpp b/source/core/rendering/pixel_reveal.hpp index 0edf4fd2..76ce0deb 100644 --- a/source/core/rendering/pixel_reveal.hpp +++ b/source/core/rendering/pixel_reveal.hpp @@ -6,11 +6,15 @@ class Surface; // Efecto de revelado pixel a pixel por filas, de arriba a abajo. -// Cada fila se revela en num_steps pasos, con píxeles aleatorios en cada paso. +// Cada fila se revela en num_steps pasos, con píxeles en orden aleatorio u ordenado (bisección). class PixelReveal { public: + // Modo de revelado: aleatorio por fila o en orden de bisección (dithering ordenado 1D) + enum class RevealMode { RANDOM, + ORDERED }; + // Constructor - PixelReveal(int width, int height, float pixels_per_second, float step_duration, int num_steps = 4); + PixelReveal(int width, int height, float pixels_per_second, float step_duration, int num_steps = 4, bool reverse = false, RevealMode mode = RevealMode::RANDOM); // Destructor definido en el .cpp para que unique_ptr funcione con forward declaration ~PixelReveal(); @@ -25,12 +29,14 @@ class PixelReveal { [[nodiscard]] bool isComplete() const; private: - std::shared_ptr cover_surface_; // Máscara negra que se va haciendo transparente - std::vector> reveal_order_; // Orden aleatorio de columnas por fila - std::vector row_step_; // Paso actual de revelado por fila (0..num_steps_) + std::shared_ptr cover_surface_; // Máscara negra que se va haciendo transparente + std::vector> reveal_order_; // Orden de columnas por fila (aleatorio u ordenado por bisección) + std::vector row_step_; // Paso actual de revelado por fila (0..num_steps_) int width_; int height_; float pixels_per_second_; // Filas reveladas por segundo float step_duration_; // Segundos por paso dentro de una fila int num_steps_; // Número de pasos de revelado por fila + bool reverse_; // Si true: transparente → negro (ocultar); si false: negro → transparente (revelar) + RevealMode mode_; // Modo de revelado: aleatorio u ordenado por bisección }; diff --git a/source/game/defaults.hpp b/source/game/defaults.hpp index 0e2f9e32..70e0a1c8 100644 --- a/source/game/defaults.hpp +++ b/source/game/defaults.hpp @@ -90,9 +90,9 @@ constexpr int GAMEPAD_BUTTON_JUMP = SDL_GAMEPAD_BUTTON_WEST; // Botón s // --- KIOSK --- namespace Kiosk { -constexpr bool ENABLED = false; // Modo kiosko desactivado por defecto -constexpr const char* TEXT = ""; // Texto del modo kiosko por defecto -constexpr bool INFINITE_LIVES = false; // Vidas infinitas en modo kiosko desactivadas por defecto +constexpr bool ENABLED = false; // Modo kiosko desactivado por defecto +constexpr const char* TEXT = ""; // Texto del modo kiosko por defecto +constexpr bool INFINITE_LIVES = false; // Vidas infinitas en modo kiosko desactivadas por defecto } // namespace Kiosk // --- GAME (posición y habitación inicial) --- @@ -100,21 +100,21 @@ namespace Game { namespace Room { #ifdef _DEBUG - constexpr const char* INITIAL = "51.yaml"; // Habitación de inicio en debug +constexpr const char* INITIAL = "51.yaml"; // Habitación de inicio en debug #else - constexpr const char* INITIAL = "03.yaml"; // Habitación de inicio en release +constexpr const char* INITIAL = "03.yaml"; // Habitación de inicio en release #endif } // namespace Room namespace Player { #ifdef _DEBUG - constexpr int SPAWN_X = 26 * Tile::SIZE; // Posición X inicial en debug - constexpr int SPAWN_Y = 10 * Tile::SIZE; // Posición Y inicial en debug - constexpr SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación inicial en debug +constexpr int SPAWN_X = 26 * Tile::SIZE; // Posición X inicial en debug +constexpr int SPAWN_Y = 10 * Tile::SIZE; // Posición Y inicial en debug +constexpr SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación inicial en debug #else - constexpr int SPAWN_X = 25 * Tile::SIZE; // Posición X inicial en release - constexpr int SPAWN_Y = 13 * Tile::SIZE; // Posición Y inicial en release - constexpr SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación inicial en release +constexpr int SPAWN_X = 25 * Tile::SIZE; // Posición X inicial en release +constexpr int SPAWN_Y = 13 * Tile::SIZE; // Posición Y inicial en release +constexpr SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación inicial en release #endif } // namespace Player diff --git a/source/game/entities/player.cpp b/source/game/entities/player.cpp index 7055de59..a98f868a 100644 --- a/source/game/entities/player.cpp +++ b/source/game/entities/player.cpp @@ -872,14 +872,14 @@ auto Player::getProjection(Direction direction, float displacement) -> SDL_FRect .x = x_ + displacement, .y = y_, .w = std::ceil(std::fabs(displacement)), // Para evitar que tenga una anchura de 0 pixels - .h = HEIGHT - 1}; // -1 para dar ventana de 2px en aperturas de altura exacta + .h = HEIGHT - 1}; // -1 para dar ventana de 2px en aperturas de altura exacta case Direction::RIGHT: return { .x = x_ + WIDTH, .y = y_, .w = std::ceil(displacement), // Para evitar que tenga una anchura de 0 pixels - .h = HEIGHT - 1}; // -1 para dar ventana de 2px en aperturas de altura exacta + .h = HEIGHT - 1}; // -1 para dar ventana de 2px en aperturas de altura exacta case Direction::UP: return { diff --git a/source/game/entities/player.hpp b/source/game/entities/player.hpp index 407e2a3f..e70f4b94 100644 --- a/source/game/entities/player.hpp +++ b/source/game/entities/player.hpp @@ -99,7 +99,7 @@ class Player { auto getRect() -> SDL_FRect { return {x_, y_, WIDTH, HEIGHT}; } // Obtiene el rectangulo que delimita al jugador auto getCollider() -> SDL_FRect& { return collider_box_; } // Obtiene el rectangulo de colision del jugador auto getSpawnParams() -> SpawnData { return {.x = x_, .y = y_, .vx = vx_, .vy = vy_, .last_grounded_position = last_grounded_position_, .state = state_, .flip = sprite_->getFlip()}; } // Obtiene el estado de reaparición del jugador - void setColor(Uint8 color = 0); // Establece el color del jugador (0 = automático según cheats) + void setColor(Uint8 color = 0); // Establece el color del jugador (0 = automático según cheats) void setRoom(std::shared_ptr room) { room_ = std::move(room); } // Establece la habitación en la que se encuentra el jugador //[[nodiscard]] auto isAlive() const -> bool { return is_alive_ || (Options::cheats.invincible == Options::Cheat::State::ENABLED); } // Comprueba si el jugador esta vivo [[nodiscard]] auto isAlive() const -> bool { return is_alive_; } // Comprueba si el jugador esta vivo diff --git a/source/game/options.hpp b/source/game/options.hpp index 894af94d..2e67b590 100644 --- a/source/game/options.hpp +++ b/source/game/options.hpp @@ -55,9 +55,9 @@ struct Stats { // Estructura para el modo kiosko struct Kiosk { - bool enabled{Defaults::Kiosk::ENABLED}; // Indica si el modo kiosko está activo - std::string text{Defaults::Kiosk::TEXT}; // Texto a mostrar en el modo kiosko - bool infinite_lives{Defaults::Kiosk::INFINITE_LIVES}; // Indica si el jugador tiene vidas infinitas en modo kiosko + bool enabled{Defaults::Kiosk::ENABLED}; // Indica si el modo kiosko está activo + std::string text{Defaults::Kiosk::TEXT}; // Texto a mostrar en el modo kiosko + bool infinite_lives{Defaults::Kiosk::INFINITE_LIVES}; // Indica si el jugador tiene vidas infinitas en modo kiosko }; // Estructura con opciones de la ventana diff --git a/source/game/scene_manager.hpp b/source/game/scene_manager.hpp index d59618dd..f5f3dfb1 100644 --- a/source/game/scene_manager.hpp +++ b/source/game/scene_manager.hpp @@ -34,7 +34,7 @@ enum class Options { // --- Variables de estado globales --- #ifdef _DEBUG -inline Scene current = Scene::ENDING; // Escena actual +inline Scene current = Scene::CREDITS; // Escena actual inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual #else inline Scene current = Scene::LOGO; // Escena actual diff --git a/source/game/scenes/credits.cpp b/source/game/scenes/credits.cpp index 65a5b307..3812b7fb 100644 --- a/source/game/scenes/credits.cpp +++ b/source/game/scenes/credits.cpp @@ -31,11 +31,9 @@ Credits::Credits() SceneManager::options = SceneManager::Options::NONE; shining_sprite_->setPos({194, 174, 8, 8}); - // Cambia el color del borde - Screen::get()->setBorderColor(static_cast(PaletteColor::BLACK)); - - // Escribe el texto en la textura - fillTexture(); + Screen::get()->setBorderColor(static_cast(PaletteColor::BLACK)); // Cambia el color del borde + fillTexture(); // Escribe el texto en la textura + Audio::get()->playMusic("title.ogg"); // Inicia la musica } // Comprueba el manejador de eventos diff --git a/source/game/scenes/credits.hpp b/source/game/scenes/credits.hpp index 7cb8d6b9..c78d6e56 100644 --- a/source/game/scenes/credits.hpp +++ b/source/game/scenes/credits.hpp @@ -48,9 +48,9 @@ class Credits { static constexpr float TOTAL_DURATION = 20.0F; // 1200 frames @ 60fps static constexpr float SHINE_START_TIME = 12.833F; // 770 frames @ 60fps static constexpr float FADE_OUT_START = 19.167F; // 1150 frames @ 60fps - static constexpr float PIXELS_PER_SECOND = 15.0F; // Filas reveladas por segundo (REVEAL_SPEED/8*2 = 60/8*2 = 15) - static constexpr float STEP_DURATION = 2.0F / 60.0F; // Segundos por paso de revelado (2 frames @ 60fps) - static constexpr int REVEAL_STEPS = 16; // Pasos de revelado por fila (más pasos = efecto más visible) + static constexpr float PIXELS_PER_SECOND = 15.0F; // Filas reveladas por segundo (REVEAL_SPEED/8*2 = 60/8*2 = 15) + static constexpr float STEP_DURATION = 2.0F / 60.0F; // Segundos por paso de revelado (2 frames @ 60fps) + static constexpr int REVEAL_STEPS = 16; // Pasos de revelado por fila (más pasos = efecto más visible) // --- Métodos privados --- void update(); // Actualiza las variables diff --git a/source/game/scenes/ending.cpp b/source/game/scenes/ending.cpp index c3ac4f95..834010f0 100644 --- a/source/game/scenes/ending.cpp +++ b/source/game/scenes/ending.cpp @@ -2,8 +2,6 @@ #include -#include // Para min - #include "core/audio/audio.hpp" // Para Audio #include "core/input/global_inputs.hpp" // Para check #include "core/input/input.hpp" // Para Input @@ -16,7 +14,6 @@ #include "core/system/global_events.hpp" // Para check #include "game/options.hpp" // Para Options, options, OptionsGame, SectionS... #include "game/scene_manager.hpp" // Para SceneManager -#include "utils/defines.hpp" // Para GAME_SPEED #include "utils/delta_timer.hpp" // Para DeltaTimer #include "utils/utils.hpp" // Para PaletteColor @@ -30,9 +27,7 @@ Ending::Ending() iniPics(); // Inicializa las imagenes iniScenes(); // Inicializa las escenas - Screen::get()->setBorderColor(static_cast(PaletteColor::BLACK)); // Cambia el color del borde - cover_surface_ = std::make_shared(Options::game.width, Options::game.height + 8); // Crea la textura para cubrir el texto - fillCoverTexture(); // Rellena la textura para la cortinilla + Screen::get()->setBorderColor(static_cast(PaletteColor::BLACK)); // Cambia el color del borde } // Destructor @@ -81,7 +76,9 @@ void Ending::render() { } // Dibuja la cortinilla de cambio de escena - renderCoverTexture(); + if (scene_cover_) { + scene_cover_->render(0, 0); + } } // Vuelca el contenido del renderizador en pantalla @@ -107,9 +104,10 @@ void Ending::transitionToState(State new_state) { state_ = new_state; state_time_ = 0.0F; - // Al cambiar a una escena, resetear fadeout_time_ + // Al cambiar a una escena, resetear la cortinilla de salida y el contador de fade if (new_state != State::WARMING_UP && new_state != State::ENDING) { fadeout_time_ = 0.0F; + scene_cover_.reset(); } } @@ -127,9 +125,12 @@ void Ending::updateState(float delta_time) { case State::SCENE_0: checkChangeScene(); - // Actualizar fadeout_time_ si estamos cerca del final if (state_time_ >= SCENE_0_DURATION - FADEOUT_START_OFFSET) { fadeout_time_ += delta_time; + if (!scene_cover_) { + scene_cover_ = std::make_unique(Options::game.width, Options::game.height, COVER_PIXELS_PER_SECOND, STEP_DURATION, COVER_STEPS, true); + } + scene_cover_->update(fadeout_time_); } break; @@ -137,6 +138,10 @@ void Ending::updateState(float delta_time) { checkChangeScene(); if (state_time_ >= SCENE_1_DURATION - FADEOUT_START_OFFSET) { fadeout_time_ += delta_time; + if (!scene_cover_) { + scene_cover_ = std::make_unique(Options::game.width, Options::game.height, COVER_PIXELS_PER_SECOND, STEP_DURATION, COVER_STEPS, true); + } + scene_cover_->update(fadeout_time_); } break; @@ -144,6 +149,10 @@ void Ending::updateState(float delta_time) { checkChangeScene(); if (state_time_ >= SCENE_2_DURATION - FADEOUT_START_OFFSET) { fadeout_time_ += delta_time; + if (!scene_cover_) { + scene_cover_ = std::make_unique(Options::game.width, Options::game.height, COVER_PIXELS_PER_SECOND, STEP_DURATION, COVER_STEPS, true); + } + scene_cover_->update(fadeout_time_); } break; @@ -151,6 +160,10 @@ void Ending::updateState(float delta_time) { checkChangeScene(); if (state_time_ >= SCENE_3_DURATION - FADEOUT_START_OFFSET) { fadeout_time_ += delta_time; + if (!scene_cover_) { + scene_cover_ = std::make_unique(Options::game.width, Options::game.height, COVER_PIXELS_PER_SECOND, STEP_DURATION, COVER_STEPS, true); + } + scene_cover_->update(fadeout_time_); } break; @@ -158,6 +171,10 @@ void Ending::updateState(float delta_time) { checkChangeScene(); if (state_time_ >= SCENE_4_DURATION - FADEOUT_START_OFFSET) { fadeout_time_ += delta_time; + if (!scene_cover_) { + scene_cover_ = std::make_unique(Options::game.width, Options::game.height, COVER_PIXELS_PER_SECOND, STEP_DURATION, COVER_STEPS, true); + } + scene_cover_->update(fadeout_time_); } break; @@ -432,42 +449,3 @@ void Ending::checkChangeScene() { } } } - -// Rellena la textura para la cortinilla -void Ending::fillCoverTexture() { - // Rellena la textura que cubre el texto con color transparente - auto previuos_renderer = Screen::get()->getRendererSurface(); - Screen::get()->setRendererSurface(cover_surface_); - cover_surface_->clear(static_cast(PaletteColor::TRANSPARENT)); - - // Los primeros 8 pixels crea una malla - const auto COLOR = static_cast(PaletteColor::BLACK); - auto surface = Screen::get()->getRendererSurface(); - for (int i = 0; i < 256; i += 2) { - surface->putPixel(i + 0, Options::game.height + 0, COLOR); - surface->putPixel(i + 1, Options::game.height + 1, COLOR); - surface->putPixel(i + 0, Options::game.height + 2, COLOR); - surface->putPixel(i + 1, Options::game.height + 3, COLOR); - - surface->putPixel(i, Options::game.height + 4, COLOR); - surface->putPixel(i, Options::game.height + 6, COLOR); - } - - // El resto se rellena de color sólido - SDL_FRect rect = {0, 0, 256, Options::game.height}; - surface->fillRect(&rect, COLOR); - - Screen::get()->setRendererSurface(previuos_renderer); -} - -// Dibuja la cortinilla de cambio de escena -void Ending::renderCoverTexture() { - if (fadeout_time_ > 0.0F) { - // Convertir fadeout_time_ a equivalente de cover_counter_ @ 60fps - const float FADEOUT_COUNTER = std::min(fadeout_time_ * 60.0F, 100.0F); - - SDL_FRect src_rect = {0.0F, 200.0F - (FADEOUT_COUNTER * 2.0F), 256.0F, FADEOUT_COUNTER * 2.0F}; - SDL_FRect dst_rect = {0.0F, 0.0F, 256.0F, FADEOUT_COUNTER * 2.0F}; - cover_surface_->render(&src_rect, &dst_rect); - } -} \ No newline at end of file diff --git a/source/game/scenes/ending.hpp b/source/game/scenes/ending.hpp index 9684cbea..15f3a4fd 100644 --- a/source/game/scenes/ending.hpp +++ b/source/game/scenes/ending.hpp @@ -57,21 +57,22 @@ class Ending { }; // --- Constantes de tiempo (basado en 60 FPS) --- - static constexpr float WARMUP_DURATION = 3.333F; // 200 frames @ 60fps - static constexpr float FADEOUT_DURATION = 1.667F; // 100 frames @ 60fps - static constexpr float SCENE_0_DURATION = 16.667F; // 1000 frames @ 60fps - static constexpr float SCENE_1_DURATION = 23.333F; // 1400 frames @ 60fps - static constexpr float SCENE_2_DURATION = 16.667F; // 1000 frames @ 60fps - static constexpr float SCENE_3_DURATION = 13.333F; // 800 frames @ 60fps - static constexpr float SCENE_4_DURATION = 16.667F; // 1000 frames @ 60fps - static constexpr float TEXT_PIXELS_PER_SECOND = 30.0F; // Filas de texto reveladas por segundo - static constexpr float IMAGE_PIXELS_PER_SECOND = 60.0F; // Filas de imagen reveladas por segundo - static constexpr float STEP_DURATION = 2.0F / 60.0F; // Segundos por paso de revelado (2 frames @ 60fps) - static constexpr int REVEAL_STEPS = 10; // Pasos de revelado por fila (más pasos = efecto más visible) - static constexpr float TEXT_LAPSE = 1.333F; // 80 frames @ 60fps - static constexpr float FADEOUT_START_OFFSET = 1.667F; // Inicio fade-out 100 frames antes del fin - static constexpr float ENDING_DURATION = 2.0F; // Duración del estado ENDING (2 segundos) - static constexpr int MUSIC_FADE_DURATION = 1800; // Fade de audio en milisegundos (1.8 segundos) + static constexpr float WARMUP_DURATION = 3.333F; // 200 frames @ 60fps + static constexpr float SCENE_0_DURATION = 16.667F; // 1000 frames @ 60fps + static constexpr float SCENE_1_DURATION = 23.333F; // 1400 frames @ 60fps + static constexpr float SCENE_2_DURATION = 16.667F; // 1000 frames @ 60fps + static constexpr float SCENE_3_DURATION = 13.333F; // 800 frames @ 60fps + static constexpr float SCENE_4_DURATION = 16.667F; // 1000 frames @ 60fps + static constexpr float TEXT_PIXELS_PER_SECOND = 30.0F; // Filas de texto reveladas por segundo + static constexpr float IMAGE_PIXELS_PER_SECOND = 60.0F; // Filas de imagen reveladas por segundo + static constexpr float STEP_DURATION = 2.0F / 60.0F; // Segundos por paso de revelado (2 frames @ 60fps) + static constexpr int REVEAL_STEPS = 4; // Pasos de revelado por fila + static constexpr float TEXT_LAPSE = 1.333F; // 80 frames @ 60fps + static constexpr float FADEOUT_START_OFFSET = 1.667F; // Inicio cortinilla 100 frames antes del fin + static constexpr float COVER_PIXELS_PER_SECOND = 120.0F; // Filas cubiertas por segundo + static constexpr int COVER_STEPS = 4; // Pasos por fila + static constexpr float ENDING_DURATION = 2.0F; // Duración del estado ENDING (2 segundos) + static constexpr int MUSIC_FADE_DURATION = 1800; // Fade de audio en milisegundos (1.8 segundos) // --- Métodos --- void update(); // Actualiza el objeto @@ -85,22 +86,20 @@ class Ending { void transitionToState(State new_state); // Transición entre estados void updateSpriteCovers(); // Actualiza las cortinillas de los elementos void checkChangeScene(); // Comprueba si se ha de cambiar de escena - void fillCoverTexture(); // Rellena la textura para la cortinilla - void renderCoverTexture(); // Dibuja la cortinilla de cambio de escena void updateMusicVolume() const; // Actualiza el volumen de la música // --- Variables miembro --- // Objetos y punteros a recursos - std::shared_ptr cover_surface_; // Surface para cubrir el texto - std::unique_ptr delta_timer_; // Timer para time-based update - std::vector sprite_texts_; // Vector con los sprites de texto con su cortinilla - std::vector sprite_pics_; // Vector con los sprites de imágenes con su cortinilla - std::vector scenes_; // Vector con los textos e imágenes de cada escena + std::unique_ptr scene_cover_; // Cortinilla de salida (negro sobre la escena) + std::unique_ptr delta_timer_; // Timer para time-based update + std::vector sprite_texts_; // Vector con los sprites de texto con su cortinilla + std::vector sprite_pics_; // Vector con los sprites de imágenes con su cortinilla + std::vector scenes_; // Vector con los textos e imágenes de cada escena // Variables de estado State state_{State::WARMING_UP}; // Estado actual float state_time_{0.0F}; // Tiempo acumulado en el estado actual float total_time_{0.0F}; // Tiempo total acumulado desde el inicio - float fadeout_time_{0.0F}; // Tiempo acumulado para el fade-out + float fadeout_time_{0.0F}; // Tiempo acumulado para la cortinilla de salida int current_scene_{0}; // Escena actual (0-4) }; \ No newline at end of file diff --git a/source/game/scenes/game.cpp b/source/game/scenes/game.cpp index caf964c8..bed69227 100644 --- a/source/game/scenes/game.cpp +++ b/source/game/scenes/game.cpp @@ -15,6 +15,7 @@ #include "core/resources/resource_cache.hpp" // Para ResourceRoom, Resource #include "core/resources/resource_list.hpp" // Para Asset #include "core/system/global_events.hpp" // Para check +#include "game/defaults.hpp" // Para Defaults::Game #include "game/gameplay/cheevos.hpp" // Para Cheevos #include "game/gameplay/item_tracker.hpp" // Para ItemTracker #include "game/gameplay/room.hpp" // Para Room, RoomData @@ -26,7 +27,6 @@ #include "game/ui/notifier.hpp" // Para Notifier, NotificationText, CHEEVO_NO... #include "utils/defines.hpp" // Para Tile::SIZE, PlayArea::HEIGHT, RoomBorder::BOTTOM #include "utils/utils.hpp" // Para PaletteColor, stringToColor -#include "game/defaults.hpp" // Para Defaults::Game #ifdef _DEBUG #include "core/system/debug.hpp" // Para Debug @@ -40,8 +40,7 @@ Game::Game(Mode mode) stats_(std::make_shared(Resource::List::get()->get("stats.csv"), Resource::List::get()->get("stats_buffer.csv"))), mode_(mode), current_room_(Defaults::Game::Room::INITIAL), - spawn_data_(Player::SpawnData(Defaults::Game::Player::SPAWN_X, Defaults::Game::Player::SPAWN_Y, 0, 0, 0, Player::State::ON_GROUND, Defaults::Game::Player::SPAWN_FLIP)) -{ + spawn_data_(Player::SpawnData(Defaults::Game::Player::SPAWN_X, Defaults::Game::Player::SPAWN_Y, 0, 0, 0, Player::State::ON_GROUND, Defaults::Game::Player::SPAWN_FLIP)) { // Crea objetos e inicializa variables ItemTracker::init(); demoInit();