migrat Ending a time based

This commit is contained in:
2025-10-30 22:57:43 +01:00
parent 99893a0c83
commit 3680ff3935
3 changed files with 256 additions and 104 deletions

View File

@@ -10,20 +10,17 @@
#include "core/rendering/surface_sprite.hpp" // Para SSprite
#include "core/rendering/text.hpp" // Para Text, TEXT_STROKE
#include "core/resources/resource.hpp" // Para Resource
#include "core/system/global_events.hpp" // Para check
#include "external/jail_audio.h" // Para JA_SetVolume, JA_PlayMusic, JA_StopMusic
#include "game/options.hpp" // Para Options, options, OptionsGame, SectionS...
#include "game/scene_manager.hpp" // Para SceneManager
#include "utils/defines.hpp" // Para GAME_SPEED
#include "core/system/global_events.hpp" // Para check
#include "utils/delta_timer.hpp" // Para DeltaTimer
#include "utils/utils.hpp" // Para PaletteColor
// Constructor
Ending::Ending()
: counter_(-1),
pre_counter_(0),
cover_counter_(0),
ticks_(0),
current_scene_(0) {
: delta_timer_(std::make_unique<DeltaTimer>()) {
SceneManager::current = SceneManager::Scene::ENDING;
SceneManager::options = SceneManager::Options::NONE;
@@ -48,29 +45,26 @@ Ending::Ending()
// Actualiza el objeto
void Ending::update() {
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
if (SDL_GetTicks() - ticks_ > GAME_SPEED) {
// Actualiza el contador de ticks
ticks_ = SDL_GetTicks();
// Obtiene el delta time
current_delta_ = delta_timer_->tick();
// Comprueba las entradas
checkInput();
// Comprueba las entradas
checkInput();
// Actualiza el contador
updateCounters();
// Actualiza el tiempo total
total_time_ += current_delta_;
// Actualiza las cortinillas de los elementos
updateSpriteCovers();
// Actualiza la máquina de estados
updateState(current_delta_);
// Comprueba si se ha de cambiar de escena
checkChangeScene();
// Actualiza las cortinillas de los elementos
updateSpriteCovers();
// Actualiza el volumen de la musica
updateMusicVolume();
// Actualiza el volumen de la musica
updateMusicVolume();
// Actualiza el objeto Screen
Screen::get()->update();
}
// Actualiza el objeto Screen
Screen::get()->update(current_delta_);
}
// Dibuja el final en pantalla
@@ -81,20 +75,26 @@ void Ending::render() {
// Limpia la pantalla
Screen::get()->clearSurface(static_cast<Uint8>(PaletteColor::BLACK));
// Dibuja las imagenes de la escena
sprite_pics_.at(current_scene_).image_sprite->render();
sprite_pics_.at(current_scene_).cover_sprite->render();
// Skip rendering durante WARMING_UP
if (state_ != State::WARMING_UP) {
// Dibuja las imagenes de la escena
sprite_pics_.at(current_scene_).image_sprite->render();
sprite_pics_.at(current_scene_).cover_sprite->render();
// Dibuja los textos de la escena
for (const auto& ti : scenes_.at(current_scene_).text_index) {
if (counter_ > ti.trigger) {
sprite_texts_.at(ti.index).image_sprite->render();
sprite_texts_.at(ti.index).cover_sprite->render();
// Dibuja los textos de la escena
for (const auto& ti : scenes_.at(current_scene_).text_index) {
// Convertir trigger de frames a segundos @ 60fps
const float TRIGGER_TIME = static_cast<float>(ti.trigger) / 60.0F;
if (state_time_ > TRIGGER_TIME) {
sprite_texts_.at(ti.index).image_sprite->render();
sprite_texts_.at(ti.index).cover_sprite->render();
}
}
}
// Dibuja la cortinilla de cambio de escena
renderCoverTexture();
// Dibuja la cortinilla de cambio de escena
renderCoverTexture();
}
// Vuelca el contenido del renderizador en pantalla
Screen::get()->render();
@@ -113,6 +113,71 @@ void Ending::checkInput() {
GlobalInputs::check();
}
// Transición entre estados
void Ending::transitionToState(State new_state) {
state_ = new_state;
state_time_ = 0.0F;
// Al cambiar a una escena, resetear fadeout_time_
if (new_state != State::WARMING_UP && new_state != State::ENDING) {
fadeout_time_ = 0.0F;
}
}
// Actualiza la máquina de estados
void Ending::updateState(float delta_time) {
state_time_ += delta_time;
switch (state_) {
case State::WARMING_UP:
if (state_time_ >= WARMUP_DURATION) {
transitionToState(State::SCENE_0);
current_scene_ = 0;
}
break;
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;
}
break;
case State::SCENE_1:
checkChangeScene();
if (state_time_ >= SCENE_1_DURATION - FADEOUT_START_OFFSET) {
fadeout_time_ += delta_time;
}
break;
case State::SCENE_2:
checkChangeScene();
if (state_time_ >= SCENE_2_DURATION - FADEOUT_START_OFFSET) {
fadeout_time_ += delta_time;
}
break;
case State::SCENE_3:
checkChangeScene();
if (state_time_ >= SCENE_3_DURATION - FADEOUT_START_OFFSET) {
fadeout_time_ += delta_time;
}
break;
case State::SCENE_4:
checkChangeScene();
if (state_time_ >= SCENE_4_DURATION - FADEOUT_START_OFFSET) {
fadeout_time_ += delta_time;
}
break;
case State::ENDING:
// Transición a ENDING2
break;
}
}
// Inicializa los textos
void Ending::iniTexts() {
// Vector con los textos
@@ -370,63 +435,119 @@ void Ending::run() {
JA_SetVolume(128);
}
// Actualiza los contadores
void Ending::updateCounters() {
// Incrementa el contador
if (pre_counter_ < 200) {
pre_counter_++;
} else {
counter_++;
}
if (counter_ > scenes_[current_scene_].counter_end - 100) {
cover_counter_++;
}
}
// Actualiza las cortinillas de los elementos
void Ending::updateSpriteCovers() {
// Skip durante WARMING_UP
if (state_ == State::WARMING_UP) {
return;
}
// Actualiza la cortinilla de los textos
if (counter_ % 4 == 0) {
for (auto ti : scenes_.at(current_scene_).text_index) {
if (counter_ > ti.trigger) {
if (sprite_texts_.at(ti.index).cover_clip_desp > 0) {
sprite_texts_.at(ti.index).cover_clip_desp -= 2;
} else if (sprite_texts_.at(ti.index).cover_clip_height > 0) {
sprite_texts_.at(ti.index).cover_clip_height -= 2;
sprite_texts_.at(ti.index).cover_sprite->setY(sprite_texts_.at(ti.index).cover_sprite->getY() + 2);
}
sprite_texts_.at(ti.index).cover_sprite->setClip(0, sprite_texts_.at(ti.index).cover_clip_desp, sprite_texts_.at(ti.index).cover_sprite->getWidth(), sprite_texts_.at(ti.index).cover_clip_height);
for (const auto& ti : scenes_.at(current_scene_).text_index) {
// Convertir trigger de frames a segundos @ 60fps
const float TRIGGER_TIME = static_cast<float>(ti.trigger) / 60.0F;
if (state_time_ > TRIGGER_TIME) {
// Tiempo transcurrido desde que se activó el trigger
const float TIME_SINCE_TRIGGER = state_time_ - TRIGGER_TIME;
// Píxeles revelados: tiempo * velocidad
const float PIXELS_REVEALED = TIME_SINCE_TRIGGER * TEXT_REVEAL_SPEED;
// Obtener altura inicial de la superficie
const float INITIAL_HEIGHT = sprite_texts_.at(ti.index).image_surface->getHeight();
const float Y_INITIAL = sprite_texts_.at(ti.index).image_sprite->getY();
// Fase 1: Revelar malla decorativa (8 píxeles)
if (PIXELS_REVEALED < 8.0F) {
sprite_texts_.at(ti.index).cover_clip_desp = static_cast<int>(8.0F - PIXELS_REVEALED);
sprite_texts_.at(ti.index).cover_clip_height = static_cast<int>(INITIAL_HEIGHT);
sprite_texts_.at(ti.index).cover_sprite->setY(Y_INITIAL);
}
// Fase 2: Revelar contenido
else {
sprite_texts_.at(ti.index).cover_clip_desp = 0;
const float CONTENT_PIXELS = PIXELS_REVEALED - 8.0F;
sprite_texts_.at(ti.index).cover_clip_height = std::max(0, static_cast<int>(INITIAL_HEIGHT - CONTENT_PIXELS));
sprite_texts_.at(ti.index).cover_sprite->setY(Y_INITIAL + static_cast<int>(CONTENT_PIXELS));
}
sprite_texts_.at(ti.index).cover_sprite->setClip(
0,
sprite_texts_.at(ti.index).cover_clip_desp,
sprite_texts_.at(ti.index).cover_sprite->getWidth(),
sprite_texts_.at(ti.index).cover_clip_height
);
}
}
// Actualiza la cortinilla de las imágenes
if (counter_ % 2 == 0) {
if (sprite_pics_.at(current_scene_).cover_clip_desp > 0) {
sprite_pics_.at(current_scene_).cover_clip_desp -= 2;
} else if (sprite_pics_.at(current_scene_).cover_clip_height > 0) {
sprite_pics_.at(current_scene_).cover_clip_height -= 2;
sprite_pics_.at(current_scene_).cover_clip_height = std::max(sprite_pics_.at(current_scene_).cover_clip_height, 0);
sprite_pics_.at(current_scene_).cover_sprite->setY(sprite_pics_.at(current_scene_).cover_sprite->getY() + 2);
}
sprite_pics_.at(current_scene_).cover_sprite->setClip(0, sprite_pics_.at(current_scene_).cover_clip_desp, sprite_pics_.at(current_scene_).cover_sprite->getWidth(), sprite_pics_.at(current_scene_).cover_clip_height);
// Actualiza la cortinilla de las imágenes (revelación continua desde el inicio de la escena)
const float PIXELS_REVEALED = state_time_ * IMAGE_REVEAL_SPEED;
const float INITIAL_HEIGHT = sprite_pics_.at(current_scene_).image_surface->getHeight();
const float Y_INITIAL = sprite_pics_.at(current_scene_).image_sprite->getY();
// Fase 1: Revelar malla decorativa (8 píxeles)
if (PIXELS_REVEALED < 8.0F) {
sprite_pics_.at(current_scene_).cover_clip_desp = static_cast<int>(8.0F - PIXELS_REVEALED);
sprite_pics_.at(current_scene_).cover_clip_height = static_cast<int>(INITIAL_HEIGHT);
sprite_pics_.at(current_scene_).cover_sprite->setY(Y_INITIAL);
}
// Fase 2: Revelar contenido
else {
sprite_pics_.at(current_scene_).cover_clip_desp = 0;
const float CONTENT_PIXELS = PIXELS_REVEALED - 8.0F;
sprite_pics_.at(current_scene_).cover_clip_height = std::max(0, static_cast<int>(INITIAL_HEIGHT - CONTENT_PIXELS));
sprite_pics_.at(current_scene_).cover_sprite->setY(Y_INITIAL + static_cast<int>(CONTENT_PIXELS));
}
sprite_pics_.at(current_scene_).cover_sprite->setClip(
0,
sprite_pics_.at(current_scene_).cover_clip_desp,
sprite_pics_.at(current_scene_).cover_sprite->getWidth(),
sprite_pics_.at(current_scene_).cover_clip_height
);
}
// Comprueba si se ha de cambiar de escena
void Ending::checkChangeScene() {
if (counter_ > scenes_[current_scene_].counter_end) {
current_scene_++;
counter_ = 0;
cover_counter_ = 0;
if (current_scene_ == 5) {
// Obtener duración de la escena actual
float CURRENT_DURATION = 0.0F;
State NEXT_STATE = State::ENDING;
switch (state_) {
case State::SCENE_0:
CURRENT_DURATION = SCENE_0_DURATION;
NEXT_STATE = State::SCENE_1;
break;
case State::SCENE_1:
CURRENT_DURATION = SCENE_1_DURATION;
NEXT_STATE = State::SCENE_2;
break;
case State::SCENE_2:
CURRENT_DURATION = SCENE_2_DURATION;
NEXT_STATE = State::SCENE_3;
break;
case State::SCENE_3:
CURRENT_DURATION = SCENE_3_DURATION;
NEXT_STATE = State::SCENE_4;
break;
case State::SCENE_4:
CURRENT_DURATION = SCENE_4_DURATION;
NEXT_STATE = State::ENDING;
break;
default:
return;
}
// Comprobar si ha pasado la duración de la escena
if (state_time_ >= CURRENT_DURATION) {
if (NEXT_STATE == State::ENDING) {
// Termina el bucle
SceneManager::current = SceneManager::Scene::ENDING2;
// Mantiene los valores anteriores
current_scene_ = 4;
cover_counter_ = 100;
} else {
// Transición a la siguiente escena
current_scene_++;
transitionToState(NEXT_STATE);
}
}
}
@@ -460,20 +581,23 @@ void Ending::fillCoverTexture() {
// Dibuja la cortinilla de cambio de escena
void Ending::renderCoverTexture() {
if (cover_counter_ > 0) {
// Dibuja la textura que cubre el texto
const int OFFSET = std::min(cover_counter_, 100);
SDL_FRect src_rect = {0.0F, 200.0F - (cover_counter_ * 2.0F), 256.0F, OFFSET * 2.0F};
SDL_FRect dst_rect = {0.0F, 0.0F, 256.0F, OFFSET * 2.0F};
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);
}
}
// Actualiza el volumen de la musica
void Ending::updateMusicVolume() const {
if (current_scene_ == 4 && cover_counter_ > 0) {
const float STEP = (100.0F - cover_counter_) / 100.0F;
const int VOLUME = 128 * STEP;
if (state_ == State::SCENE_4 && 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);
const float STEP = (100.0F - FADEOUT_COUNTER) / 100.0F;
const int VOLUME = static_cast<int>(128.0F * STEP);
JA_SetVolume(VOLUME);
}
}