Files
jaildoctors_dilemma/source/game/scenes/credits.cpp

262 lines
10 KiB
C++

#include "game/scenes/credits.hpp"
#include <SDL3/SDL.h>
#include <algorithm> // Para min
#include "core/audio/audio.hpp" // Para Audio
#include "core/input/global_inputs.hpp" // Para check
#include "core/input/input.hpp" // Para Input
#include "core/rendering/screen.hpp" // Para Screen
#include "core/rendering/surface.hpp" // Para Surface
#include "core/rendering/surface_animated_sprite.hpp" // Para SAnimatedSprite
#include "core/rendering/text.hpp" // Para Text, Text::CENTER_FLAG, Text::COLOR_FLAG
#include "core/resources/resource_cache.hpp" // Para Resource
#include "core/system/global_events.hpp" // Para check
#include "game/options.hpp" // Para Options, options, OptionsGame, Sectio...
#include "game/scene_manager.hpp" // Para SceneManager
#include "utils/defines.hpp" // Para GAME_SPEED, PLAY_AREA_CENTER_X, PLAY_...
#include "utils/delta_timer.hpp" // Para DeltaTimer
#include "utils/utils.hpp" // Para PaletteColor
// Constructor
Credits::Credits()
: text_surface_(std::make_shared<Surface>(Options::game.width, Options::game.height)),
cover_surface_(std::make_shared<Surface>(Options::game.width, Options::game.height)),
shining_sprite_(std::make_shared<SurfaceAnimatedSprite>(Resource::Cache::get()->getAnimationData("shine.yaml"))),
delta_timer_(std::make_unique<DeltaTimer>()) {
// Configura la escena
SceneManager::current = SceneManager::Scene::CREDITS;
SceneManager::options = SceneManager::Options::NONE;
shining_sprite_->setPos({194, 174, 8, 8});
// Cambia el color del borde
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
// Escribe el texto en la textura
fillTexture();
}
// Comprueba el manejador de eventos
void Credits::handleEvents() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
GlobalEvents::handle(event);
}
}
// Comprueba las entradas
void Credits::handleInput() {
Input::get()->update();
GlobalInputs::handle();
}
// Inicializa los textos
void Credits::iniTexts() {
std::string keys = "CURSORS";
texts_.clear();
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"INSTRUCTIONS:", static_cast<Uint8>(PaletteColor::YELLOW)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"HELP JAILDOC TO GET BACK ALL", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"HIS PROJECTS AND GO TO THE", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"JAIL TO FINISH THEM", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"KEYS:", static_cast<Uint8>(PaletteColor::YELLOW)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({keys + " TO MOVE AND JUMP", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"F8 TOGGLE THE MUSIC", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"F11 TO PAUSE THE GAME", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"F1-F2 TO CHANGE WINDOWS SIZE", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"F3 TOGGLE FULLSCREEN", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"F9 TOOGLE THE BORDER SCREEN", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"A GAME BY JAILDESIGNER", static_cast<Uint8>(PaletteColor::YELLOW)});
texts_.push_back({"MADE ON SUMMER/FALL 2022", static_cast<Uint8>(PaletteColor::YELLOW)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"I LOVE JAILGAMES! ", static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
}
// Escribe el texto en la textura
void Credits::fillTexture() {
// Inicializa los textos
iniTexts();
// Rellena la textura de texto
auto previuos_renderer = Screen::get()->getRendererSurface();
Screen::get()->setRendererSurface(text_surface_);
text_surface_->clear(static_cast<Uint8>(PaletteColor::BLACK));
auto text = Resource::Cache::get()->getText("smb2");
// Escribe el texto en la textura
const int SIZE = text->getCharacterSize();
int pos_y = 0;
for (const auto& t : texts_) {
text->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, PLAY_AREA_CENTER_X, pos_y * SIZE, t.label, 1, t.color);
pos_y++;
}
// Escribe el corazón
const int TEXT_LENGHT = text->length(texts_[22].label, 1) - text->length(" ", 1); // Se resta el ultimo caracter que es un espacio
const int POS_X = ((PLAY_AREA_WIDTH - TEXT_LENGHT) / 2) + TEXT_LENGHT;
text->writeColored(POS_X, 176, "}", static_cast<Uint8>(PaletteColor::BRIGHT_RED));
Screen::get()->setRendererSurface(previuos_renderer);
// Recoloca el sprite del brillo
shining_sprite_->setPosX(POS_X + 2);
// Rellena la textura que cubre el texto con color transparente
cover_surface_->clear(static_cast<Uint8>(PaletteColor::TRANSPARENT));
// Los primeros 8 pixels crea una malla
auto color = static_cast<Uint8>(PaletteColor::BLACK);
for (int i = 0; i < 256; i += 2) {
cover_surface_->putPixel(i, 0, color);
cover_surface_->putPixel(i, 2, color);
cover_surface_->putPixel(i, 4, color);
cover_surface_->putPixel(i, 6, color);
cover_surface_->putPixel(i + 1, 5, color);
cover_surface_->putPixel(i + 1, 7, color);
}
// El resto se rellena de color sólido
SDL_FRect rect = {0, 8, 256, 192};
cover_surface_->fillRect(&rect, color);
}
// Actualiza las variables
void Credits::update() {
const float DELTA_TIME = delta_timer_->tick();
total_time_ += DELTA_TIME; // Actualiza el tiempo total
handleEvents(); // Comprueba los eventos
handleInput(); // Comprueba las entradas
updateState(DELTA_TIME); // Actualiza la máquina de estados
// Actualiza el sprite con el brillo si está después del tiempo de inicio
if (reveal_time_ > SHINE_START_TIME) {
shining_sprite_->update(DELTA_TIME);
}
Audio::update(); // Actualiza el objeto Audio
Screen::get()->update(DELTA_TIME); // Actualiza el objeto Screen
}
// Transición entre estados
void Credits::transitionToState(State new_state) {
state_ = new_state;
state_time_ = 0.0F;
}
// Actualiza la máquina de estados
void Credits::updateState(float delta_time) {
state_time_ += delta_time;
switch (state_) {
case State::REVEALING_TEXT:
reveal_time_ += delta_time; // Incrementa reveal_time durante revelación
if (state_time_ >= REVEAL_PHASE_1_DURATION) {
transitionToState(State::PAUSE_1);
}
break;
case State::PAUSE_1:
// reveal_time_ NO incrementa durante pausa (se congela)
if (state_time_ >= PAUSE_DURATION) {
transitionToState(State::REVEALING_TEXT_2);
}
break;
case State::REVEALING_TEXT_2:
reveal_time_ += delta_time; // Incrementa reveal_time durante revelación
if (state_time_ >= REVEAL_PHASE_2_DURATION) {
transitionToState(State::PAUSE_2);
}
break;
case State::PAUSE_2:
// reveal_time_ NO incrementa durante pausa (se congela)
if (state_time_ >= PAUSE_DURATION) {
transitionToState(State::REVEALING_TEXT_3);
}
break;
case State::REVEALING_TEXT_3:
reveal_time_ += delta_time; // Incrementa reveal_time durante revelación
if (state_time_ >= REVEAL_PHASE_3_DURATION) {
transitionToState(State::PAUSE_3);
}
break;
case State::PAUSE_3:
// reveal_time_ NO incrementa durante pausa (se congela)
if (state_time_ >= PAUSE_DURATION) {
transitionToState(State::DISPLAYING_WITH_SHINE);
}
break;
case State::DISPLAYING_WITH_SHINE:
reveal_time_ += delta_time; // Incrementa reveal_time durante revelación
if (state_time_ >= DISPLAY_WITH_SHINE_DURATION) {
transitionToState(State::FADING_OUT);
}
break;
case State::FADING_OUT:
reveal_time_ += delta_time; // Incrementa reveal_time durante fade
if (state_time_ >= FADE_OUT_DURATION) {
transitionToState(State::EXITING);
}
break;
case State::EXITING:
SceneManager::current = SceneManager::Scene::DEMO;
break;
}
}
// Dibuja en pantalla
void Credits::render() {
// Prepara para empezar a dibujar en la textura de juego
Screen::get()->start();
// Limpia la pantalla
Screen::get()->clearSurface(static_cast<Uint8>(PaletteColor::BLACK));
if (state_ != State::EXITING) {
// Dibuja la textura con el texto en pantalla
text_surface_->render(0, 0);
// Dibuja la textura que cubre el texto
// OFFSET basado en reveal_time_ (que se congela durante pausas, como counter_ original)
const float OFFSET = std::min(reveal_time_ * REVEAL_SPEED / 8.0F, 192.0F / 2.0F);
SDL_FRect src_rect = {0.0F, 0.0F, 256.0F, 192.0F - (OFFSET * 2.0F)};
cover_surface_->render(0, static_cast<int>(OFFSET * 2.0F), &src_rect);
// Dibuja el sprite con el brillo
shining_sprite_->render(1, static_cast<Uint8>(PaletteColor::BRIGHT_WHITE));
}
// Vuelca el contenido del renderizador en pantalla
Screen::get()->render();
}
// Bucle para el logo del juego
void Credits::run() {
while (SceneManager::current == SceneManager::Scene::CREDITS) {
update();
render();
}
}