#include "instructions.h" #include // Para SDL_BLENDMODE_BLEND #include // Para SDL_PollEvent, SDL_Event, SDL_QUIT #include // Para SDL_PIXELFORMAT_RGBA8888 #include // Para SDL_GetTicks #include // Para SDL_WINDOWEVENT_SIZE_CHANGED #include // Para max #include // Para move #include "fade.h" // Para Fade, FadeMode, FadeType #include "global_inputs.h" // Para check #include "input.h" // Para Input #include "jail_audio.h" // Para JA_GetMusicState, JA_Music_state #include "lang.h" // Para getText #include "param.h" // Para Param, param, ParamGame, ParamFade #include "resource.h" // Para Resource #include "screen.h" // Para Screen #include "section.h" // Para Name, name, Options, options #include "sprite.h" // Para Sprite #include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR, TEXT_... #include "texture.h" // Para Texture #include "tiled_bg.h" // Para TiledBG, TiledBGMode #include "utils.h" // Para Color, shdw_txt_color, Zone, no_color // Constructor Instructions::Instructions() : renderer_(Screen::get()->getRenderer()), texture_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), text_(std::make_unique(Resource::get()->getTexture("smb2.gif"), Resource::get()->getTextFile("smb2.txt"))), tiled_bg_(std::make_unique((SDL_Rect){0, 0, param.game.width, param.game.height}, TiledBGMode::STATIC)), fade_(std::make_unique()) { // Crea un backbuffer para el renderizador SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND); // Crea una textura para el texto fijo SDL_SetTextureBlendMode(texture_, SDL_BLENDMODE_BLEND); // Inicializa variables section::name = section::Name::INSTRUCTIONS; view_ = {0, 0, param.game.width, param.game.height}; // Inicializa objetos fade_->setColor(fade_color.r, fade_color.g, fade_color.b); fade_->setType(FadeType::FULLSCREEN); fade_->setPost(param.fade.post_duration); fade_->setMode(FadeMode::IN); fade_->activate(); // Rellena la textura de texto fillTexture(); // Inicializa los sprites de los items iniSprites(); } // Destructor Instructions::~Instructions() { item_textures_.clear(); sprites_.clear(); SDL_DestroyTexture(backbuffer_); SDL_DestroyTexture(texture_); } // Inicializa los sprites de los items void Instructions::iniSprites() { // Inicializa las texturas item_textures_.emplace_back(Resource::get()->getTexture("item_points1_disk.png")); item_textures_.emplace_back(Resource::get()->getTexture("item_points2_gavina.png")); item_textures_.emplace_back(Resource::get()->getTexture("item_points3_pacmar.png")); item_textures_.emplace_back(Resource::get()->getTexture("item_clock.png")); item_textures_.emplace_back(Resource::get()->getTexture("item_coffee.png")); // Inicializa los sprites for (int i = 0; i < (int)item_textures_.size(); ++i) { auto sprite = std::make_unique(item_textures_[i], 0, 0, param.game.item_size, param.game.item_size); sprite->setPosition((SDL_Point){sprite_pos_.x, sprite_pos_.y + ((param.game.item_size + item_space_) * i)}); sprites_.push_back(std::move(sprite)); } } // Actualiza los sprites void Instructions::updateSprites() { SDL_Rect src_rect = {0, 0, param.game.item_size, param.game.item_size}; // Disquito src_rect.y = param.game.item_size * (((counter_ + 12) / 36) % 2); sprites_[0]->setSpriteClip(src_rect); // Gavina src_rect.y = param.game.item_size * (((counter_ + 9) / 36) % 2); sprites_[1]->setSpriteClip(src_rect); // Pacmar src_rect.y = param.game.item_size * (((counter_ + 6) / 36) % 2); sprites_[2]->setSpriteClip(src_rect); // Time Stopper src_rect.y = param.game.item_size * (((counter_ + 3) / 36) % 2); sprites_[3]->setSpriteClip(src_rect); // Coffee src_rect.y = param.game.item_size * (((counter_ + 0) / 36) % 2); sprites_[4]->setSpriteClip(src_rect); } // Rellena la textura de texto void Instructions::fillTexture() { const int desp_x = param.game.item_size + 8; // Modifica el renderizador para pintar en la textura auto temp = SDL_GetRenderTarget(renderer_); SDL_SetRenderTarget(renderer_, texture_); // Limpia la textura SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0); SDL_RenderClear(renderer_); // Constantes constexpr int num_lines = 4; constexpr int num_item_lines = 4; constexpr int num_post_headers = 2; constexpr int num_pre_headers = 1; constexpr int space_post_header = 20; constexpr int space_pre_header = 28; const int space_between_lines = text_->getCharacterSize() * 1.5f; const int space_between_item_lines = param.game.item_size + item_space_; const int space_new_paragraph = space_between_lines * 0.5f; const int size = (num_lines * space_between_lines) + (num_item_lines * space_between_item_lines) + (num_post_headers * space_post_header) + (num_pre_headers * space_pre_header) + (space_new_paragraph); const int first_line = (param.game.height - size) / 2; // Calcula cual es el texto más largo de las descripciones de los items int lenght = 0; for (int i = 17; i <= 21; ++i) { const int l = text_->lenght(lang::getText(i)); lenght = l > lenght ? l : lenght; } const int anchor_item = (param.game.width - (lenght + desp_x)) / 2; // Escribe el texto de las instrucciones text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, first_line, lang::getText(11), 1, orange_color, 1, shdw_txt_color); const int anchor1 = first_line + space_post_header; text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_between_lines * 0, lang::getText(12), 1, no_color, 1, shdw_txt_color); text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_between_lines * 1, lang::getText(13), 1, no_color, 1, shdw_txt_color); text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_new_paragraph + space_between_lines * 2, lang::getText(14), 1, no_color, 1, shdw_txt_color); text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_new_paragraph + space_between_lines * 3, lang::getText(15), 1, no_color, 1, shdw_txt_color); // Escribe el texto de los objetos y sus puntos const int anchor2 = anchor1 + space_pre_header + space_new_paragraph + space_between_lines * 3; text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor2, lang::getText(16), 1, orange_color, 1, shdw_txt_color); const int anchor3 = anchor2 + space_post_header; // const int anchor4 = anchor3 + ((param.game.item_size + text->getCharacterSize()) / 2); text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 0, lang::getText(17), shdw_txt_color); text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 1, lang::getText(18), shdw_txt_color); text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 2, lang::getText(19), shdw_txt_color); text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 3, lang::getText(20), shdw_txt_color); text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 4, lang::getText(21), shdw_txt_color); // Deja el renderizador como estaba SDL_SetRenderTarget(renderer_, temp); // Da valor a la variable sprite_pos_.x = anchor_item; sprite_pos_.y = anchor3 - ((param.game.item_size - text_->getCharacterSize()) / 2); } // Rellena el backbuffer void Instructions::fillBackbuffer() { // Modifica el renderizador para pintar en la textura auto temp = SDL_GetRenderTarget(renderer_); SDL_SetRenderTarget(renderer_, backbuffer_); // Limpia la textura SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0); SDL_RenderClear(renderer_); // Coloca el texto de fondo SDL_RenderCopy(renderer_, texture_, nullptr, nullptr); // Dibuja los sprites for (auto &sprite : sprites_) { sprite->render(); } // Deja el renderizador como estaba SDL_SetRenderTarget(renderer_, temp); } // Actualiza las variables void Instructions::update() { constexpr int TICKS_SPEED = 15; if (SDL_GetTicks() - ticks_ > TICKS_SPEED) { // Actualiza el contador de ticks ticks_ = SDL_GetTicks(); // Mantiene la música sonando if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED)) JA_PlayMusic(Resource::get()->getMusic("title.ogg")); // Actualiza el objeto screen Screen::get()->update(); // Incrementa el contador counter_++; // Actualiza los sprites updateSprites(); // Actualiza el mosaico de fondo tiled_bg_->update(); // Actualiza el objeto "fade" fade_->update(); // Comprueba si el contador ha llegado al final if (counter_ == counter_end_) { section::name = section::Name::TITLE; section::options = section::Options::TITLE_1; } } } // Pinta en pantalla void Instructions::render() { // Rellena el backbuffer fillBackbuffer(); // Prepara para empezar a dibujar en la textura de juego Screen::get()->start(); // Limpia la pantalla Screen::get()->clean(bg_color); // Dibuja el mosacico de fondo tiled_bg_->render(); // Establece la ventana del backbuffer view_.y = std::max(0, param.game.height - counter_ + 100); // Copia la textura y el backbuffer al renderizador SDL_RenderCopy(renderer_, backbuffer_, nullptr, &view_); fade_->render(); // Vuelca el contenido del renderizador en pantalla Screen::get()->blit(); } // Recarga todas las texturas void Instructions::reloadTextures() { for (auto &texture : item_textures_) { texture->reLoad(); } text_->reLoadTexture(); fillTexture(); } // Comprueba los eventos void Instructions::checkEvents() { // Comprueba los eventos que hay en la cola SDL_Event event; while (SDL_PollEvent(&event)) { // Evento de salida de la aplicación if (event.type == SDL_QUIT) { section::name = section::Name::QUIT; section::options = section::Options::QUIT_FROM_EVENT; break; } // Comprueba si se ha cambiado el tamaño de la ventana else if (event.type == SDL_WINDOWEVENT) { if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { reloadTextures(); } } } } // Comprueba las entradas void Instructions::checkInput() { // Comprueba si se ha pulsado cualquier botón (de los usados para jugar) if (Input::get()->checkAnyButtonPressed()) { JA_StopMusic(); section::name = section::Name::TITLE; section::options = section::Options::TITLE_1; return; } // Comprueba los inputs que se pueden introducir en cualquier sección del juego globalInputs::check(); } // Bucle para la pantalla de instrucciones void Instructions::run() { while (section::name == section::Name::INSTRUCTIONS) { checkInput(); update(); checkEvents(); // Tiene que ir antes del render render(); } }