482 lines
17 KiB
C++
482 lines
17 KiB
C++
#include "game/scenes/ending2.hpp"
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
#include <algorithm> // Para max, replace
|
|
|
|
#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/surface_moving_sprite.hpp" // Para SMovingSprite
|
|
#include "core/rendering/text.hpp" // Para Text
|
|
#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 GAMECANVAS_CENTER_X, GAMECANVAS_CENTER_Y
|
|
#include "utils/delta_timer.hpp" // Para DeltaTimer
|
|
#include "utils/utils.hpp" // Para PaletteColor, stringToColor
|
|
|
|
// Constructor
|
|
Ending2::Ending2()
|
|
: delta_timer_(std::make_unique<DeltaTimer>()),
|
|
state_{EndingState::PRE_CREDITS, STATE_PRE_CREDITS_DURATION} {
|
|
// Establece la escena
|
|
SceneManager::current = SceneManager::Scene::ENDING2;
|
|
SceneManager::options = SceneManager::Options::NONE;
|
|
|
|
// Inicializa el vector de colores
|
|
const std::vector<std::string> COLORS = {"white", "yellow", "cyan", "green", "magenta", "red", "blue", "black"};
|
|
for (const auto& color : COLORS) {
|
|
colors_.push_back(stringToColor(color));
|
|
}
|
|
|
|
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK)); // Cambia el color del borde
|
|
iniSpriteList(); // Inicializa la lista de sprites
|
|
loadSprites(); // Carga todos los sprites desde una lista
|
|
placeSprites(); // Coloca los sprites en su sito
|
|
createSpriteTexts(); // Crea los sprites con las texturas con los textos
|
|
createTexts(); // Crea los sprites con las texturas con los textos del final
|
|
}
|
|
|
|
// Actualiza el objeto
|
|
void Ending2::update() {
|
|
const float DELTA_TIME = delta_timer_->tick();
|
|
|
|
handleEvents(); // Comprueba los eventos
|
|
handleInput(); // Comprueba las entradas
|
|
|
|
updateState(DELTA_TIME); // Actualiza el estado
|
|
|
|
switch (state_.state) {
|
|
case EndingState::CREDITS:
|
|
// Actualiza los sprites, los textos y los textos del final
|
|
updateSprites(DELTA_TIME);
|
|
updateTextSprites(DELTA_TIME);
|
|
updateTexts(DELTA_TIME);
|
|
break;
|
|
|
|
case EndingState::FADING:
|
|
// Actualiza el fade final
|
|
updateFinalFade();
|
|
break;
|
|
|
|
default:
|
|
// No hacer nada si el estado no corresponde a un caso manejado
|
|
break;
|
|
}
|
|
|
|
Audio::update(); // Actualiza el objeto Audio
|
|
Screen::get()->update(DELTA_TIME); // Actualiza el objeto Screen
|
|
}
|
|
|
|
// Dibuja el final en pantalla
|
|
void Ending2::render() {
|
|
// Prepara para empezar a dibujar en la surface de juego
|
|
Screen::get()->start();
|
|
|
|
// Limpia la pantalla
|
|
Screen::get()->clearSurface(static_cast<Uint8>(PaletteColor::BLACK));
|
|
|
|
// Dibuja los sprites
|
|
renderSprites();
|
|
|
|
// Dibuja los sprites con el texto
|
|
renderSpriteTexts();
|
|
|
|
// Dibuja los sprites con el texto del final
|
|
renderTexts();
|
|
|
|
// Dibuja una trama arriba y abajo
|
|
auto color = static_cast<Uint8>(PaletteColor::BLACK);
|
|
auto surface = Screen::get()->getRendererSurface();
|
|
for (int i = 0; i < 256; i += 2) {
|
|
surface->putPixel(i + 0, 0, color);
|
|
surface->putPixel(i + 1, 1, color);
|
|
surface->putPixel(i + 0, 2, color);
|
|
surface->putPixel(i + 1, 3, color);
|
|
|
|
surface->putPixel(i, 4, color);
|
|
surface->putPixel(i, 6, color);
|
|
|
|
surface->putPixel(i + 0, 191, color);
|
|
surface->putPixel(i + 1, 190, color);
|
|
surface->putPixel(i + 0, 189, color);
|
|
surface->putPixel(i + 1, 188, color);
|
|
|
|
surface->putPixel(i, 187, color);
|
|
surface->putPixel(i, 185, color);
|
|
}
|
|
|
|
// Vuelca el contenido del renderizador en pantalla
|
|
Screen::get()->render();
|
|
}
|
|
|
|
// Comprueba el manejador de eventos
|
|
void Ending2::handleEvents() {
|
|
SDL_Event event;
|
|
while (SDL_PollEvent(&event)) {
|
|
GlobalEvents::handle(event);
|
|
}
|
|
}
|
|
|
|
// Comprueba las entradas
|
|
void Ending2::handleInput() {
|
|
Input::get()->update();
|
|
GlobalInputs::handle();
|
|
}
|
|
|
|
// Bucle principal
|
|
void Ending2::run() {
|
|
Audio::get()->playMusic("ending2.ogg");
|
|
|
|
while (SceneManager::current == SceneManager::Scene::ENDING2) {
|
|
update();
|
|
render();
|
|
}
|
|
|
|
Audio::get()->stopMusic();
|
|
}
|
|
|
|
// Actualiza el estado
|
|
void Ending2::updateState(float delta_time) {
|
|
state_time_ += delta_time;
|
|
|
|
switch (state_.state) {
|
|
case EndingState::PRE_CREDITS:
|
|
if (state_time_ >= STATE_PRE_CREDITS_DURATION) {
|
|
transitionToState(EndingState::CREDITS);
|
|
}
|
|
break;
|
|
|
|
case EndingState::CREDITS:
|
|
if (texts_.back()->getPosY() <= GAMECANVAS_CENTER_Y) {
|
|
transitionToState(EndingState::POST_CREDITS);
|
|
}
|
|
break;
|
|
|
|
case EndingState::POST_CREDITS:
|
|
if (state_time_ >= STATE_POST_CREDITS_DURATION) {
|
|
transitionToState(EndingState::FADING);
|
|
}
|
|
break;
|
|
|
|
case EndingState::FADING:
|
|
if (state_time_ >= STATE_FADE_DURATION) {
|
|
SceneManager::current = SceneManager::Scene::LOGO;
|
|
SceneManager::options = SceneManager::Options::LOGO_TO_LOADING_SCREEN;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Transición entre estados
|
|
void Ending2::transitionToState(EndingState new_state) {
|
|
state_.state = new_state;
|
|
state_time_ = 0.0F;
|
|
|
|
// Actualizar duración según el nuevo estado
|
|
switch (new_state) {
|
|
case EndingState::PRE_CREDITS:
|
|
state_.duration = STATE_PRE_CREDITS_DURATION;
|
|
break;
|
|
case EndingState::POST_CREDITS:
|
|
state_.duration = STATE_POST_CREDITS_DURATION;
|
|
break;
|
|
case EndingState::FADING:
|
|
state_.duration = STATE_FADE_DURATION;
|
|
// Al entrar en FADING, iniciar fade de audio
|
|
Audio::get()->fadeOutMusic(MUSIC_FADE_DURATION);
|
|
break;
|
|
case EndingState::CREDITS:
|
|
state_.duration = 0.0F; // CREDITS no tiene duración fija, termina cuando el último texto llega al centro
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Inicializa la lista de sprites
|
|
void Ending2::iniSpriteList() {
|
|
// Reinicia el vector
|
|
sprite_list_.clear();
|
|
|
|
// Añade los valores
|
|
sprite_list_.emplace_back("bin");
|
|
sprite_list_.emplace_back("floppy");
|
|
sprite_list_.emplace_back("bird");
|
|
sprite_list_.emplace_back("chip");
|
|
sprite_list_.emplace_back("jeannine");
|
|
sprite_list_.emplace_back("spark");
|
|
sprite_list_.emplace_back("code");
|
|
sprite_list_.emplace_back("paco");
|
|
sprite_list_.emplace_back("elsa");
|
|
sprite_list_.emplace_back("z80");
|
|
|
|
sprite_list_.emplace_back("bell");
|
|
sprite_list_.emplace_back("dong");
|
|
|
|
sprite_list_.emplace_back("amstrad_cs");
|
|
sprite_list_.emplace_back("breakout");
|
|
|
|
sprite_list_.emplace_back("flying_arounder");
|
|
sprite_list_.emplace_back("stopped_arounder");
|
|
sprite_list_.emplace_back("walking_arounder");
|
|
sprite_list_.emplace_back("arounders_door");
|
|
sprite_list_.emplace_back("arounders_machine");
|
|
|
|
sprite_list_.emplace_back("abad");
|
|
sprite_list_.emplace_back("abad_bell");
|
|
sprite_list_.emplace_back("lord_abad");
|
|
|
|
sprite_list_.emplace_back("bat");
|
|
sprite_list_.emplace_back("batman_bell");
|
|
sprite_list_.emplace_back("batman_fire");
|
|
sprite_list_.emplace_back("batman");
|
|
|
|
sprite_list_.emplace_back("demon");
|
|
sprite_list_.emplace_back("heavy");
|
|
sprite_list_.emplace_back("dimallas");
|
|
sprite_list_.emplace_back("guitar");
|
|
|
|
sprite_list_.emplace_back("jailbattle_alien");
|
|
sprite_list_.emplace_back("jailbattle_human");
|
|
|
|
sprite_list_.emplace_back("jailer_#1");
|
|
sprite_list_.emplace_back("jailer_#2");
|
|
sprite_list_.emplace_back("jailer_#3");
|
|
sprite_list_.emplace_back("bry");
|
|
sprite_list_.emplace_back("upv_student");
|
|
|
|
sprite_list_.emplace_back("lamp");
|
|
sprite_list_.emplace_back("robot");
|
|
sprite_list_.emplace_back("congo");
|
|
sprite_list_.emplace_back("crosshair");
|
|
sprite_list_.emplace_back("tree_thing");
|
|
|
|
sprite_list_.emplace_back("matatunos");
|
|
sprite_list_.emplace_back("tuno");
|
|
|
|
sprite_list_.emplace_back("mummy");
|
|
sprite_list_.emplace_back("sam");
|
|
|
|
sprite_list_.emplace_back("qvoid");
|
|
sprite_list_.emplace_back("sigmasua");
|
|
|
|
sprite_list_.emplace_back("tv_panel");
|
|
sprite_list_.emplace_back("tv");
|
|
|
|
sprite_list_.emplace_back("spider");
|
|
sprite_list_.emplace_back("shock");
|
|
sprite_list_.emplace_back("wave");
|
|
|
|
sprite_list_.emplace_back("player");
|
|
}
|
|
|
|
// Carga todos los sprites desde una lista
|
|
void Ending2::loadSprites() {
|
|
// Inicializa variables
|
|
sprite_max_width_ = 0;
|
|
sprite_max_height_ = 0;
|
|
|
|
// Carga los sprites
|
|
for (const auto& file : sprite_list_) {
|
|
sprites_.emplace_back(std::make_shared<SurfaceAnimatedSprite>(Resource::Cache::get()->getAnimations(file + ".ani")));
|
|
sprite_max_width_ = std::max(sprites_.back()->getWidth(), sprite_max_width_);
|
|
sprite_max_height_ = std::max(sprites_.back()->getHeight(), sprite_max_height_);
|
|
}
|
|
}
|
|
|
|
// Actualiza los sprites
|
|
void Ending2::updateSprites(float delta) {
|
|
for (const auto& sprite : sprites_) {
|
|
sprite->update(delta);
|
|
}
|
|
}
|
|
|
|
// Actualiza los sprites de texto
|
|
void Ending2::updateTextSprites(float delta) {
|
|
for (const auto& sprite : sprite_texts_) {
|
|
sprite->update(delta);
|
|
}
|
|
}
|
|
|
|
// Actualiza los sprites de texto del final
|
|
void Ending2::updateTexts(float delta) {
|
|
for (const auto& sprite : texts_) {
|
|
sprite->update(delta);
|
|
}
|
|
}
|
|
|
|
// Dibuja los sprites
|
|
void Ending2::renderSprites() {
|
|
const auto COLOR_A = static_cast<Uint8>(PaletteColor::RED);
|
|
for (const auto& sprite : sprites_) {
|
|
const bool A = sprite->getRect().y + sprite->getRect().h > 0;
|
|
const bool B = sprite->getRect().y < Options::game.height;
|
|
if (A && B) {
|
|
sprite->render(1, COLOR_A);
|
|
}
|
|
}
|
|
|
|
// Pinta el ultimo elemento de otro color
|
|
const auto COLOR_B = static_cast<Uint8>(PaletteColor::WHITE);
|
|
sprites_.back()->render(1, COLOR_B);
|
|
}
|
|
|
|
// Dibuja los sprites con el texto
|
|
void Ending2::renderSpriteTexts() {
|
|
const auto COLOR = static_cast<Uint8>(PaletteColor::WHITE);
|
|
for (const auto& sprite : sprite_texts_) {
|
|
const bool A = sprite->getRect().y + sprite->getRect().h > 0;
|
|
const bool B = sprite->getRect().y < Options::game.height;
|
|
if (A && B) {
|
|
sprite->render(1, COLOR);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dibuja los sprites con el texto del final
|
|
void Ending2::renderTexts() {
|
|
for (const auto& sprite : texts_) {
|
|
const bool A = sprite->getRect().y + sprite->getRect().h > 0;
|
|
const bool B = sprite->getRect().y < Options::game.height;
|
|
if (A && B) {
|
|
sprite->render();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Coloca los sprites en su sito
|
|
void Ending2::placeSprites() {
|
|
for (int i = 0; i < static_cast<int>(sprites_.size()); ++i) {
|
|
const float X = i % 2 == 0 ? FIRST_COL : SECOND_COL;
|
|
const float Y = ((i / 1) * (sprite_max_height_ + DIST_SPRITE_TEXT + Resource::Cache::get()->getText("smb2")->getCharacterSize() + DIST_SPRITE_SPRITE)) + Options::game.height + INITIAL_Y_OFFSET;
|
|
const float W = sprites_.at(i)->getWidth();
|
|
const float H = sprites_.at(i)->getHeight();
|
|
const float DX = -(W / 2);
|
|
const float DY = sprite_max_height_ - H;
|
|
|
|
sprites_.at(i)->setPos({X + DX, Y + DY, W, H});
|
|
sprites_.at(i)->setVelY(SPRITE_DESP_SPEED);
|
|
}
|
|
|
|
// Recoloca el sprite del jugador, que es el último de la lista
|
|
const float X = (Options::game.width - sprites_.back()->getWidth()) / 2;
|
|
const float Y = sprites_.back()->getPosY() + (sprite_max_height_ * 2);
|
|
sprites_.back()->setPos(X, Y);
|
|
sprites_.back()->setCurrentAnimation("walk");
|
|
}
|
|
|
|
// Crea los sprites con las texturas con los textos
|
|
void Ending2::createSpriteTexts() {
|
|
// Crea los sprites de texto a partir de la lista
|
|
for (size_t i = 0; i < sprite_list_.size(); ++i) {
|
|
auto text = Resource::Cache::get()->getText("smb2");
|
|
|
|
// Procesa y ajusta el texto del sprite actual
|
|
std::string txt = sprite_list_[i];
|
|
std::ranges::replace(txt, '_', ' '); // Reemplaza '_' por ' '
|
|
if (txt == "player") {
|
|
txt = "JAILDOCTOR"; // Reemplaza "player" por "JAILDOCTOR"
|
|
}
|
|
|
|
// Calcula las dimensiones del texto
|
|
const float W = text->length(txt, 1);
|
|
const float H = text->getCharacterSize();
|
|
|
|
// Determina la columna y la posición X del texto
|
|
const float X = (i == sprite_list_.size() - 1)
|
|
? (GAMECANVAS_CENTER_X - (W / 2))
|
|
: ((i % 2 == 0 ? FIRST_COL : SECOND_COL) - (W / 2));
|
|
|
|
// Calcula la posición Y del texto en base a la posición y altura del sprite
|
|
const float Y = sprites_.at(i)->getPosY() + sprites_.at(i)->getHeight() + DIST_SPRITE_TEXT;
|
|
|
|
// Crea la surface
|
|
auto surface = std::make_shared<Surface>(W, H);
|
|
auto previuos_renderer = Screen::get()->getRendererSurface();
|
|
Screen::get()->setRendererSurface(surface);
|
|
text->write(0, 0, txt);
|
|
|
|
// Crea el sprite
|
|
SDL_FRect pos = {X, Y, W, H};
|
|
sprite_texts_.emplace_back(std::make_shared<SurfaceMovingSprite>(surface, pos));
|
|
sprite_texts_.back()->setVelY(SPRITE_DESP_SPEED);
|
|
Screen::get()->setRendererSurface(previuos_renderer);
|
|
}
|
|
}
|
|
|
|
// Crea los sprites con las texturas con los textos del final
|
|
void Ending2::createTexts() {
|
|
// Crea los primeros textos
|
|
std::vector<std::string> list;
|
|
list.emplace_back("STARRING");
|
|
|
|
auto text = Resource::Cache::get()->getText("smb2");
|
|
|
|
// Crea los sprites de texto a partir de la lista
|
|
for (size_t i = 0; i < list.size(); ++i) {
|
|
// Calcula constantes
|
|
const float W = text->length(list[i], 1);
|
|
const float H = text->getCharacterSize();
|
|
const float X = GAMECANVAS_CENTER_X;
|
|
const float DX = -(W / 2);
|
|
const float Y = Options::game.height + (text->getCharacterSize() * (i * TEXT_SPACING_MULTIPLIER));
|
|
|
|
// Crea la surface
|
|
auto surface = std::make_shared<Surface>(W, H);
|
|
auto previuos_renderer = Screen::get()->getRendererSurface();
|
|
Screen::get()->setRendererSurface(surface);
|
|
text->write(0, 0, list[i]);
|
|
|
|
// Crea el sprite
|
|
SDL_FRect pos = {X + DX, Y, W, H};
|
|
texts_.emplace_back(std::make_shared<SurfaceMovingSprite>(surface, pos));
|
|
texts_.back()->setVelY(SPRITE_DESP_SPEED);
|
|
Screen::get()->setRendererSurface(previuos_renderer);
|
|
}
|
|
|
|
// Crea los últimos textos
|
|
// El primer texto va a continuación del ultimo spriteText
|
|
const int START = sprite_texts_.back()->getPosY() + (text->getCharacterSize() * 15);
|
|
list.clear();
|
|
list.emplace_back("THANK YOU");
|
|
list.emplace_back("FOR PLAYING!");
|
|
|
|
// Crea los sprites de texto a partir de la lista
|
|
for (size_t i = 0; i < list.size(); ++i) {
|
|
// Calcula constantes
|
|
const float W = text->length(list[i], 1);
|
|
const float H = text->getCharacterSize();
|
|
const float X = GAMECANVAS_CENTER_X;
|
|
const float DX = -(W / 2);
|
|
const float Y = START + (text->getCharacterSize() * (i * TEXT_SPACING_MULTIPLIER));
|
|
|
|
// Crea la surface
|
|
auto surface = std::make_shared<Surface>(W, H);
|
|
auto previuos_renderer = Screen::get()->getRendererSurface();
|
|
Screen::get()->setRendererSurface(surface);
|
|
text->write(0, 0, list[i]);
|
|
|
|
// Crea el sprite
|
|
SDL_FRect pos = {X + DX, Y, W, H};
|
|
texts_.emplace_back(std::make_shared<SurfaceMovingSprite>(surface, pos));
|
|
texts_.back()->setVelY(SPRITE_DESP_SPEED);
|
|
Screen::get()->setRendererSurface(previuos_renderer);
|
|
}
|
|
}
|
|
|
|
// Actualiza el fade final
|
|
void Ending2::updateFinalFade() {
|
|
for (const auto& sprite : texts_) {
|
|
sprite->getSurface()->fadeSubPalette(0);
|
|
}
|
|
}
|