#include "instructions.h" #include "param.h" #include // Constructor Instructions::Instructions(Screen *screen, Asset *asset, Input *input, options_t *options, section_t *section, JA_Music_t *music) { // Copia los punteros this->screen = screen; this->asset = asset; this->input = input; this->section = section; this->music = music; this->options = options; renderer = screen->getRenderer(); // Crea objetos eventHandler = new SDL_Event(); text = new Text(asset->get("smb2.gif"), asset->get("smb2.txt"), renderer); tiledbg = new Tiledbg(renderer, asset, {0, 0, param.game.width, param.game.height}, TILED_MODE_STATIC); fade = new Fade(renderer); // Crea un backbuffer para el renderizador backbuffer = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height); SDL_SetTextureBlendMode(backbuffer, SDL_BLENDMODE_BLEND); // Crea una textura para el texto fijo texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height); SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); // Inicializa variables section->name = SECTION_PROG_INSTRUCTIONS; ticks = 0; ticksSpeed = 15; counter = 0; counterEnd = 700; view = {0, 0, param.game.width, param.game.height}; spritePos = {0, 0}; itemSpace = 2; // Inicializa objetos fade->setColor(fadeColor.r, fadeColor.g, fadeColor.b); fade->setType(FADE_FULLSCREEN); fade->setPost(param.fade.postDuration); fade->setMode(FADE_IN); fade->activate(); // Rellena la textura de texto fillTexture(); // Inicializa los sprites de los items iniSprites(); } // Destructor Instructions::~Instructions() { for (auto texture : itemTextures) { texture->unload(); delete texture; } itemTextures.clear(); for (auto sprite : sprites) { delete sprite; } sprites.clear(); delete eventHandler; delete text; delete tiledbg; delete fade; SDL_DestroyTexture(backbuffer); SDL_DestroyTexture(texture); } // Inicializa los sprites de los items void Instructions::iniSprites() { // Inicializa las texturas Texture *item1 = new Texture(renderer, asset->get("item_points1_disk.png")); itemTextures.push_back(item1); Texture *item2 = new Texture(renderer, asset->get("item_points2_gavina.png")); itemTextures.push_back(item2); Texture *item3 = new Texture(renderer, asset->get("item_points3_pacmar.png")); itemTextures.push_back(item3); Texture *item4 = new Texture(renderer, asset->get("item_clock.png")); itemTextures.push_back(item4); Texture *item5 = new Texture(renderer, asset->get("item_coffee.png")); itemTextures.push_back(item5); // Inicializa los sprites for (int i = 0; i < (int)itemTextures.size(); ++i) { Sprite *sprite = new Sprite(0, 0, param.game.itemSize, param.game.itemSize, itemTextures[i]); sprite->setPos((SDL_Point){spritePos.x, spritePos.y + ((param.game.itemSize + itemSpace) * i)}); sprites.push_back(sprite); } } // Actualiza los sprites void Instructions::updateSprites() { SDL_Rect srcRect = {0, 0, param.game.itemSize, param.game.itemSize}; // Disquito srcRect.y = param.game.itemSize * (((counter + 12) / 36) % 2); sprites[0]->setSpriteClip(srcRect); // Gavineixon srcRect.y = param.game.itemSize * (((counter + 9) / 36) % 2); sprites[1]->setSpriteClip(srcRect); // Pacmar srcRect.y = param.game.itemSize * (((counter + 6) / 36) % 2); sprites[2]->setSpriteClip(srcRect); // Time Stopper srcRect.y = param.game.itemSize * (((counter + 3) / 36) % 2); sprites[3]->setSpriteClip(srcRect); // Coffee srcRect.y = param.game.itemSize * (((counter + 0) / 36) % 2); sprites[4]->setSpriteClip(srcRect); } // Rellena la textura de texto void Instructions::fillTexture() { const int despX = param.game.itemSize + 8; // Modifica el renderizador para pintar en la textura SDL_Texture *temp = SDL_GetRenderTarget(renderer); SDL_SetRenderTarget(renderer, texture); // Limpia la textura SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_RenderClear(renderer); // Constantes const int numLines = 4; const int numItemLines = 4; const int numPostHeaders = 2; const int numPreHeaders = 1; const int spacePostHeader = 20; const int spacePreHeader = 28; const int spaceBetweenLines = text->getCharacterSize() * 1.5f; const int spaceBetweenItemLines = param.game.itemSize + itemSpace; const int spaceNewParagraph = spaceBetweenLines * 0.5f; const int size = (numLines * spaceBetweenLines) + (numItemLines * spaceBetweenItemLines) + (numPostHeaders * spacePostHeader) + (numPreHeaders * spacePreHeader) + (spaceNewParagraph); const int firstLine = (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 anchorItem = (param.game.width - (lenght + despX)) / 2; // Escribe el texto de las instrucciones text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param.game.gameArea.centerX, firstLine, lang::getText(11), 1, orangeColor, 1, shdwTxtColor); const int anchor1 = firstLine + spacePostHeader; text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param.game.gameArea.centerX, anchor1 + spaceBetweenLines * 0, lang::getText(12), 1, noColor, 1, shdwTxtColor); text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param.game.gameArea.centerX, anchor1 + spaceBetweenLines * 1, lang::getText(13), 1, noColor, 1, shdwTxtColor); text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param.game.gameArea.centerX, anchor1 + spaceNewParagraph + spaceBetweenLines * 2, lang::getText(14), 1, noColor, 1, shdwTxtColor); text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param.game.gameArea.centerX, anchor1 + spaceNewParagraph + spaceBetweenLines * 3, lang::getText(15), 1, noColor, 1, shdwTxtColor); // Escribe el texto de los objetos y sus puntos const int anchor2 = anchor1 + spacePreHeader + spaceNewParagraph + spaceBetweenLines * 3; text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param.game.gameArea.centerX, anchor2, lang::getText(16), 1, orangeColor, 1, shdwTxtColor); const int anchor3 = anchor2 + spacePostHeader; // const int anchor4 = anchor3 + ((param.game.itemSize + text->getCharacterSize()) / 2); text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 0, lang::getText(17), shdwTxtColor); text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 1, lang::getText(18), shdwTxtColor); text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 2, lang::getText(19), shdwTxtColor); text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 3, lang::getText(20), shdwTxtColor); text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 4, lang::getText(21), shdwTxtColor); // Deja el renderizador como estaba SDL_SetRenderTarget(renderer, temp); // Da valor a la variable spritePos.x = anchorItem; spritePos.y = anchor3 - ((param.game.itemSize - text->getCharacterSize()) / 2); } // Rellena el backbuffer void Instructions::fillBackbuffer() { // Modifica el renderizador para pintar en la textura SDL_Texture *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() { // Actualiza las variables if (SDL_GetTicks() - ticks > ticksSpeed) { // 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(music); // Actualiza el objeto screen screen->update(); // Incrementa el contador counter++; // Actualiza los sprites updateSprites(); // Actualiza el mosaico de fondo tiledbg->update(); // Actualiza el objeto "fade" fade->update(); // Comprueba si el contador ha llegado al final if (counter == counterEnd) { section->name = SECTION_PROG_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->start(); // Limpia la pantalla screen->clean(bgColor); // Dibuja el mosacico de fondo tiledbg->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->blit(); } // Recarga todas las texturas void Instructions::reloadTextures() { for (auto tex : itemTextures) { tex->reLoad(); } text->reLoadTexture(); fillTexture(); } // Comprueba los eventos void Instructions::checkEvents() { // Comprueba los eventos que hay en la cola while (SDL_PollEvent(eventHandler) != 0) { // Evento de salida de la aplicación if (eventHandler->type == SDL_QUIT) { section->name = SECTION_PROG_QUIT; break; } // Comprueba si se ha cambiado el tamaño de la ventana else if (eventHandler->type == SDL_WINDOWEVENT) { if (eventHandler->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { reloadTextures(); } } } } // Comprueba las entradas void Instructions::checkInput() { // Comprueba si se sale con el teclado if (input->checkInput(input_exit, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD)) { quit(SECTION_OPTIONS_QUIT_NORMAL); return; } // Comprueba si se ha pulsado cualquier botón (de los usados para jugar) if (input->checkAnyButtonPressed()) { JA_StopMusic(); section->name = SECTION_PROG_TITLE; section->options = SECTION_OPTIONS_TITLE_1; return; } for (int i = 0; i < input->getNumControllers(); ++i) { // Comprueba si se sale con el mando if (input->checkModInput(input_service, input_exit, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i)) { quit(SECTION_OPTIONS_QUIT_SHUTDOWN); return; } // Comprueba si se va a resetear el juego if (input->checkModInput(input_service, input_reset, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i)) { section->name = SECTION_PROG_LOGO; screen->showNotification("Reset"); return; } // Comprueba si se va a activar o desactivar el audio if (input->checkModInput(input_service, input_mute, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i)) { options->audio.sound.enabled = options->audio.music.enabled = !options->audio.music.enabled; JA_EnableMusic(options->audio.music.enabled); JA_EnableSound(options->audio.sound.enabled); screen->showNotification("Audio " + boolToOnOff(options->audio.music.enabled)); return; } } // Comprueba el input para el resto de objetos screen->checkInput(); } // Bucle para la pantalla de instrucciones void Instructions::run() { while (section->name == SECTION_PROG_INSTRUCTIONS) { checkInput(); update(); checkEvents(); // Tiene que ir antes del render render(); } } // Termina void Instructions::quit(int code) { if (screen->notificationsAreActive()) { section->name = SECTION_PROG_QUIT; section->options = code; } else { screen->showNotification(lang::getText(94)); } }