#include "intro.h" #include // Para SDL_BLENDMODE_BLEND, SDL_BLENDMODE_MOD #include // Para SDL_PollEvent, SDL_Event #include // Para SDL_PIXELFORMAT_RGBA8888 #include // Para SDL_FRect #include // Para SDL_SetTextureBlendMode, SDL_GetRend... #include // Para SDL_GetTicks #include // Para array #include // Para function #include // Para basic_string, string #include // Para move #include "global_events.h" // Para check #include "global_inputs.h" // Para check, update #include "jail_audio.h" // Para JA_PlayMusic, JA_StopMusic #include "lang.h" // Para getText #include "param.h" // Para Param, ParamGame, param #include "path_sprite.h" // Para PathSprite, PathType #include "resource.h" // Para Resource #include "screen.h" // Para Screen #include "section.h" // Para Name, name, Options, options #include "texture.h" // Para Texture #include "tiled_bg.h" // Para TiledBG, TiledBGMode #include "utils.h" // Para Color, Zone, easeOutQuint, BLOCK #include "writer.h" // Para Writer // Constructor Intro::Intro() : tiled_bg_(std::make_unique(param.game.game_area.rect, TiledBGMode::DIAGONAL)) { // Inicializa variables section::name = section::Name::INTRO; section::options = section::Options::NONE; // Inicializa las imagens initSprites(); // Inicializa los textos initTexts(); // Configura el fondo tiled_bg_->setSpeed(0.3f); tiled_bg_->setColor(Color(bg_color_, bg_color_, bg_color_)); } // Comprueba los eventos void Intro::checkEvents() { SDL_Event event; while (SDL_PollEvent(&event)) { globalEvents::check(event); } } // Comprueba las entradas void Intro::checkInput() { globalInputs::check(); } // Actualiza las escenas de la intro void Intro::updateScenes() { switch (scene_) { case 0: { // Primera imagen - UPV sprites_.at(0)->enable(); shadow_sprites_.at(0)->enable(); // Primer texto de la primera imagen if (sprites_.at(0)->hasFinished() && !texts_.at(0)->hasFinished()) { texts_.at(0)->setEnabled(true); } // Segundo texto de la primera imagen if (texts_.at(0)->hasFinished() && !texts_.at(1)->hasFinished()) { texts_.at(0)->setEnabled(false); texts_.at(1)->setEnabled(true); } // Tercer texto de la primera imagen if (texts_.at(1)->hasFinished() && !texts_.at(2)->hasFinished()) { texts_.at(1)->setEnabled(false); texts_.at(2)->setEnabled(true); } // Fin de la primera escena if (texts_.at(2)->hasFinished()) { texts_.at(2)->setEnabled(false); scene_++; } break; } case 1: { // Segunda imagen - Máquina sprites_.at(1)->enable(); shadow_sprites_.at(1)->enable(); // Primer texto de la segunda imagen if (sprites_.at(1)->hasFinished() && !texts_.at(3)->hasFinished()) { texts_.at(3)->setEnabled(true); } // Fin de la segunda escena if (texts_.at(3)->hasFinished()) { texts_.at(3)->setEnabled(false); scene_++; } break; } case 2: { // Tercera imagen junto con primer texto - GRITO if (!texts_.at(4)->hasFinished()) { sprites_.at(2)->enable(); shadow_sprites_.at(2)->enable(); texts_.at(4)->setEnabled(true); } // Fin de la tercera escena if (sprites_.at(2)->hasFinished() && texts_.at(4)->hasFinished()) { texts_.at(4)->setEnabled(false); scene_++; } break; } case 3: { // Cuarta imagen junto con primer texto - Reflexión sprites_.at(3)->enable(); shadow_sprites_.at(3)->enable(); if (!texts_.at(5)->hasFinished()) { texts_.at(5)->setEnabled(true); } // Segundo texto de la cuarta imagen if (texts_.at(5)->hasFinished() && !texts_.at(6)->hasFinished()) { texts_.at(5)->setEnabled(false); texts_.at(6)->setEnabled(true); } // Fin de la cuarta escena if (sprites_.at(3)->hasFinished() && texts_.at(6)->hasFinished()) { texts_.at(6)->setEnabled(false); scene_++; } break; } case 4: { // Quinta imagen - Patada sprites_.at(4)->enable(); shadow_sprites_.at(4)->enable(); // Primer texto de la quinta imagen if (!texts_.at(7)->hasFinished()) { texts_.at(7)->setEnabled(true); } // Fin de la quinta escena if (sprites_.at(4)->hasFinished() && texts_.at(7)->hasFinished()) { texts_.at(7)->setEnabled(false); scene_++; } break; } case 5: { // Sexta imagen junto con texto - Globos de café sprites_.at(5)->enable(); shadow_sprites_.at(5)->enable(); if (!texts_.at(8)->hasFinished()) { texts_.at(8)->setEnabled(true); } // Acaba el último texto if (texts_.at(8)->hasFinished()) { texts_.at(8)->setEnabled(false); } // Acaba la ultima imagen if (sprites_.at(5)->hasFinished() && texts_.at(8)->hasFinished()) { state_ = IntroState::POST; state_start_time_ = SDL_GetTicks(); } break; } default: break; } } // Actualiza las variables del objeto void Intro::update() { if (SDL_GetTicks() - ticks_ > param.game.speed) { // Actualiza el contador de ticks ticks_ = SDL_GetTicks(); // Actualiza el fondo tiled_bg_->update(); switch (state_) { case IntroState::SCENES: updateSprites(); updateTexts(); updateScenes(); break; case IntroState::POST: updatePostState(); break; } // Actualiza el objeto screen Screen::get()->update(); // Actualiza las variables de globalInputs globalInputs::update(); } } // Dibuja el objeto en pantalla void Intro::render() { // Prepara para empezar a dibujar en la textura de juego Screen::get()->start(); // Limpia la pantalla Screen::get()->clean(bg_color); // Dibuja el fondo tiled_bg_->render(); switch (state_) { case IntroState::SCENES: { renderSprites(); renderTexts(); break; } case IntroState::POST: break; } // Vuelca el contenido del renderizador en pantalla Screen::get()->render(); } // Bucle principal void Intro::run() { JA_PlayMusic(Resource::get()->getMusic("intro.ogg"), 0); while (section::name == section::Name::INTRO) { checkInput(); update(); checkEvents(); // Tiene que ir antes del render render(); } } // Inicializa las imagens void Intro::initSprites() { // Listado de imagenes a usar const std::array TEXTURE_LIST = { "intro1.png", "intro2.png", "intro3.png", "intro4.png", "intro5.png", "intro6.png"}; // Constantes auto texture = Resource::get()->getTexture(TEXTURE_LIST.front()); const float SPRITE_WIDTH = texture->getWidth(); const float SPRITE_HEIGHT = texture->getHeight(); const float X_DEST = param.game.game_area.center_x - SPRITE_WIDTH / 2; const float Y_DEST = param.game.game_area.first_quarter_y - (SPRITE_HEIGHT / 4); // Inicializa los sprites con las imagenes constexpr int TOTAL_SPRITES = 6; for (int i = 0; i < TOTAL_SPRITES; ++i) { auto sprite = std::make_unique(Resource::get()->getTexture(TEXTURE_LIST.at(i))); sprite->setWidth(SPRITE_WIDTH); sprite->setHeight(SPRITE_HEIGHT); sprite->setSpriteClip(0, 0, SPRITE_WIDTH, SPRITE_HEIGHT); sprites_.push_back(std::move(sprite)); } sprites_.at(0)->addPath(-SPRITE_WIDTH - 10, X_DEST, PathType::HORIZONTAL, Y_DEST, 100, easeInOutExpo, 0); sprites_.at(1)->addPath(param.game.width, X_DEST, PathType::HORIZONTAL, Y_DEST, 100, easeOutBounce, 0); sprites_.at(2)->addPath(-SPRITE_HEIGHT, Y_DEST, PathType::VERTICAL, X_DEST, 40, easeOutQuint, 0); sprites_.at(3)->addPath(param.game.height, Y_DEST, PathType::VERTICAL, X_DEST, 300, easeInOutExpo, 0); sprites_.at(4)->addPath(-SPRITE_HEIGHT, Y_DEST, PathType::VERTICAL, X_DEST, 70, easeOutElastic, 0); sprites_.at(5)->addPath(param.game.width, X_DEST, PathType::HORIZONTAL, Y_DEST, 250, easeOutQuad, 450); sprites_.at(5)->addPath(X_DEST, -SPRITE_WIDTH, PathType::HORIZONTAL, Y_DEST, 80, easeInElastic, 0); // Constantes const float BORDER = 4; const float SHADOW_SPRITE_WIDTH = SPRITE_WIDTH + BORDER; const float SHADOW_SPRITE_HEIGHT = SPRITE_HEIGHT + BORDER; const float S_X_DEST = X_DEST - BORDER / 2; const float S_Y_DEST = Y_DEST - BORDER / 2; // Crea las texturas para las imágenes traseras std::vector> shadow_textures; for (int i = 0; i < TOTAL_SPRITES; ++i) { auto shadow_texture = std::make_shared(Screen::get()->getRenderer()); shadow_texture->createBlank(SHADOW_SPRITE_WIDTH, SHADOW_SPRITE_HEIGHT, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET); shadow_texture->setBlendMode(SDL_BLENDMODE_BLEND); auto temp = SDL_GetRenderTarget(Screen::get()->getRenderer()); shadow_texture->setAsRenderTarget(Screen::get()->getRenderer()); SDL_SetRenderDrawColor(Screen::get()->getRenderer(), 0xFF, 0x00, 0x00, 0xFF); SDL_RenderClear(Screen::get()->getRenderer()); SDL_FRect rect = {BORDER / 2, BORDER / 2, SPRITE_WIDTH, SPRITE_HEIGHT}; auto inner_texture = Resource::get()->getTexture(TEXTURE_LIST.at(i))->getSDLTexture(); SDL_SetTextureBlendMode(inner_texture, SDL_BLENDMODE_MOD); SDL_RenderTexture(Screen::get()->getRenderer(), inner_texture, nullptr, &rect); SDL_SetTextureBlendMode(inner_texture, SDL_BLENDMODE_NONE); SDL_SetRenderTarget(Screen::get()->getRenderer(), temp); shadow_textures.push_back(shadow_texture); } // Inicializa los sprites para la sombra for (int i = 0; i < TOTAL_SPRITES; ++i) { auto sprite = std::make_unique(shadow_textures.at(i)); sprite->setWidth(SHADOW_SPRITE_WIDTH); sprite->setHeight(SHADOW_SPRITE_HEIGHT); sprite->setSpriteClip(0, 0, SHADOW_SPRITE_WIDTH, SHADOW_SPRITE_HEIGHT); shadow_sprites_.push_back(std::move(sprite)); } shadow_sprites_.at(0)->addPath(param.game.height + 10, S_Y_DEST, PathType::VERTICAL, S_X_DEST, 100, easeInOutExpo, 0); shadow_sprites_.at(1)->addPath(-SHADOW_SPRITE_HEIGHT, S_Y_DEST, PathType::VERTICAL, S_X_DEST, 100, easeOutBounce, 0); shadow_sprites_.at(2)->addPath(-SHADOW_SPRITE_WIDTH, S_X_DEST, PathType::HORIZONTAL, S_Y_DEST, 40, easeOutQuint, 0); shadow_sprites_.at(3)->addPath(-SHADOW_SPRITE_HEIGHT, S_Y_DEST, PathType::VERTICAL, S_X_DEST, 400, easeInOutExpo, 0); shadow_sprites_.at(4)->addPath(param.game.height, S_Y_DEST, PathType::VERTICAL, S_X_DEST, 70, easeOutElastic, 0); shadow_sprites_.at(5)->addPath(-SHADOW_SPRITE_HEIGHT, S_Y_DEST, PathType::VERTICAL, S_X_DEST, 250, easeOutQuad, 450); shadow_sprites_.at(5)->addPath(S_X_DEST, param.game.width, PathType::HORIZONTAL, S_Y_DEST, 80, easeInElastic, 0); } // Inicializa los textos void Intro::initTexts() { constexpr int TOTAL_TEXTS = 9; for (int i = 0; i < TOTAL_TEXTS; ++i) { auto w = std::make_unique(Resource::get()->getText("04b_25_metal")); w->setPosX(BLOCK * 0); w->setPosY(param.game.height - (BLOCK * 6)); w->setKerning(-2); w->setEnabled(false); w->setFinishedCounter(180); texts_.push_back(std::move(w)); } // Un dia qualsevol de l'any 2000 texts_.at(0)->setCaption(lang::getText(27)); texts_.at(0)->setSpeed(8); // Tot esta tranquil a la UPV texts_.at(1)->setCaption(lang::getText(28)); texts_.at(1)->setSpeed(8); // Fins que un desaprensiu... texts_.at(2)->setCaption(lang::getText(29)); texts_.at(2)->setSpeed(12); // HEY! ME ANE A FERME UN CORTAET... texts_.at(3)->setCaption(lang::getText(30)); texts_.at(3)->setSpeed(8); // UAAAAAAAAAAAAA!!! texts_.at(4)->setCaption(lang::getText(31)); texts_.at(4)->setSpeed(1); // Espera un moment... texts_.at(5)->setCaption(lang::getText(32)); texts_.at(5)->setSpeed(16); // Si resulta que no tinc solt! texts_.at(6)->setCaption(lang::getText(33)); texts_.at(6)->setSpeed(2); // MERDA DE MAQUINA! texts_.at(7)->setCaption(lang::getText(34)); texts_.at(7)->setSpeed(3); // Blop... blop... blop... texts_.at(8)->setCaption(lang::getText(35)); texts_.at(8)->setSpeed(20); for (auto &text : texts_) { text->center(param.game.game_area.center_x); } } // Actualiza los sprites void Intro::updateSprites() { for (auto &sprite : sprites_) { sprite->update(); } for (auto &sprite : shadow_sprites_) { sprite->update(); } } // Actualiza los textos void Intro::updateTexts() { for (auto &text : texts_) { text->update(); } } // Dibuja los sprites void Intro::renderSprites() { shadow_sprites_.at(scene_)->render(); sprites_.at(scene_)->render(); } // Dibuja los textos void Intro::renderTexts() { for (const auto &text : texts_) { text->render(); } } // Actualiza el estado POST void Intro::updatePostState() { const Uint32 ELAPSED_TIME = SDL_GetTicks() - state_start_time_; switch (post_state_) { case IntroPostState::STOP_BG: // EVENTO: Detiene el fondo después de 2 segundos if (ELAPSED_TIME >= 1000) { tiled_bg_->stopGracefully(); // Modifica el color del fondo hasta llegar a blanco if (bg_color_ <= 253) // Garantiza que no se exceda de 255 al incrementar de 2 en 2 { bg_color_ += 2; } else { bg_color_ = 255; // Asegura que bg_color_ no exceda el límite máximo } tiled_bg_->setColor(Color(bg_color_, bg_color_, bg_color_)); } // Cambia de estado si el fondo se ha detenido y recuperado el color if (tiled_bg_->isStopped() && bg_color_ == 255) { post_state_ = IntroPostState::END; state_start_time_ = SDL_GetTicks(); } break; case IntroPostState::END: // Finaliza la intro después de 1 segundo if (ELAPSED_TIME >= 1000) { JA_StopMusic(); section::name = section::Name::TITLE; section::options = section::Options::TITLE_1; } break; default: break; } }