#include "gamedirector.h" // Calcula el cuadrado de la distancia entre dos puntos double distanceSquared(int x1, int y1, int x2, int y2) { int deltaX = x2 - x1; int deltaY = y2 - y1; return deltaX * deltaX + deltaY * deltaY; } // Detector de colisiones entre dos circulos bool checkCollision(Circle &a, Circle &b) { // Calcula el radio total al cuadrado int totalRadiusSquared = a.r + b.r; totalRadiusSquared = totalRadiusSquared * totalRadiusSquared; // Si la distancia entre el centro de los circulos es inferior a la suma de sus radios if (distanceSquared(a.x, a.y, b.x, b.y) < (totalRadiusSquared)) { // Los circulos han colisionado return true; } // En caso contrario return false; } // Constructor GameDirector::GameDirector(SDL_Renderer *gRenderer) { this->gRenderer = gRenderer; for (Uint8 i = 0; i < mMaxBalloons; i++) { balloon[i] = new Balloon(gRenderer); } for (int i = 0; i < mMaxBullets; i++) { bullet[i] = new Bullet(gRenderer); } init(); } // Destructor GameDirector::~GameDirector() { // Libera los efectos de sonido Mix_FreeChunk(gPopBalloonFX); Mix_FreeChunk(gBulletFX); gPopBalloonFX = NULL; gBulletFX = NULL; // Libra la música Mix_FreeMusic(gTitleMusic); gTitleMusic = NULL; Mix_FreeMusic(gPlayingMusic); gPlayingMusic = NULL; // Libera el mando SDL_JoystickClose(gGameController); gGameController = NULL; // Libera texturas gGameBackgroundTexture->free(); gTitleBackgroundTexture->free(); gWhiteFontTexture->free(); gBlackFontTexture->free(); gMiscTexture->free(); // Libera objetos delete player; delete menuPause; delete menuTitle; for (Uint8 i = 0; i < mMaxBalloons; i++) { delete balloon[i]; } for (int i = 0; i < mMaxBullets; i++) { delete bullet[i]; } } // Iniciador void GameDirector::init() { // Carga la música del titulo gTitleMusic = Mix_LoadMUS("media/music/title.ogg"); if (gTitleMusic == NULL) { printf("Failed to load title music! SDL_mixer Error: %s\n", Mix_GetError()); } // Carga la música del juego gPlayingMusic = Mix_LoadMUS("media/music/playing.ogg"); if (gPlayingMusic == NULL) { printf("Failed to load playing music! SDL_mixer Error: %s\n", Mix_GetError()); } // Carga los efectos de sonido para la explosión de los globos gPopBalloonFX = Mix_LoadWAV("media/sound/balloon.wav"); if (gPopBalloonFX == NULL) { printf("Failed to load balloon sound effect! SDL_mixer Error: %s\n", Mix_GetError()); } // Carga los efectos de sonido para los disparos del jugador gBulletFX = Mix_LoadWAV("media/sound/bullet.wav"); if (gBulletFX == NULL) { printf("Failed to load bullet sound effect! SDL_mixer Error: %s\n", Mix_GetError()); } gGameBackgroundTexture = new LTexture(gRenderer); // Carga los gráficos del fondo del juego if (!gGameBackgroundTexture->loadFromFile("media/gfx/background.png")) { printf("Failed to load game background texture!\n"); } gTitleBackgroundTexture = new LTexture(gRenderer); // Carga los gráficos del fondo de la pantalla de titulo if (!gTitleBackgroundTexture->loadFromFile("media/gfx/title.png")) { printf("Failed to load title texture!\n"); } gMiscTexture = new LTexture(gRenderer); // Carga varios gráficos para varios propósitos if (!gMiscTexture->loadFromFile("media/gfx/misc.png")) { printf("Failed to load misc texture!\n"); } gWhiteFontTexture = new LTexture(gRenderer); // Carga los gráficos para el texto blanco if (!gWhiteFontTexture->loadFromFile("media/gfx/white_font.png")) { printf("Failed to load white font texture!\n"); } gBlackFontTexture = new LTexture(gRenderer); // Carga los gráficos para el texto negro if (!gBlackFontTexture->loadFromFile("media/gfx/black_font.png")) { printf("Failed to load black font texture!\n"); } // Comprueba los mandos if (SDL_NumJoysticks() < 1) { printf("Warning: No joysticks connected!\n"); } else { // Carga el mando gGameController = SDL_JoystickOpen(0); if (gGameController == NULL) { printf("Warning: Unable to open game controller! SDL Error: %s\n", SDL_GetError()); } printf("%i joysticks were found.\n", SDL_NumJoysticks()); std::cout << SDL_JoystickNumButtons(gGameController) << " buttons\n"; } // Variables mGameStatus = GAME_STATE_TITLE; mOldTicks = 0; mMaxBalloons = 50; mMaxBullets = 50; mGameSpeed = 15; mMenaceLevel = 0; mMenaceLevelThreshold = 7; mScore = 0; mHiScore = 0; mScoreText = std::to_string(mScore); mHiScoreText = std::to_string(mHiScore); mGetReady = true; // Objeto jugador player = new Player(gRenderer); player->init(); // Establece a cero todos los valores del vector de objetos globo resetBalloons(); // Crea dos objetos globo y los centra en el area de juego // balloon[0].init(0, BLOCK, BALLOON_4, BALLON_VELX_POSITIVE, 0); // balloon[0].allignTo(PLAY_AREA_WIDTH / 2); // balloon[1].init(0, BLOCK, BALLOON_4, BALLON_VELX_NEGATIVE, 0); // balloon[1].allignTo(PLAY_AREA_WIDTH / 2); // Con los globos creados, calcula el nivel de amenaza calculateMenaceLevel(); // Establece a cero todos los valores del vector de objetos bala resetBullets(); #ifdef TEST balloonTest.init(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, BALLOON_4, 0); balloonTest.stop(); bulletTest.init(SCREEN_WIDTH / 4, SCREEN_HEIGHT / 2, BULLET_UP); #endif // Los fondos gameBackground.init(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - (0 * BLOCK), gGameBackgroundTexture); titleBackground.init(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, gTitleBackgroundTexture); // Objetos texto, uno de cada color whiteText.init(gWhiteFontTexture); blackText.init(gBlackFontTexture); // Inicializa el objeto con el menu del titulo menuTitle = new Menu(gRenderer); menuTitle->init(0, 16 * BLOCK, MENU_SELECTOR_WHITE, MENU_BACKGROUND_TRANSPARENT); menuTitle->addItem("START"); menuTitle->addItem("EXIT"); menuTitle->setBackgroundColor(0, 0, 0, 255); menuTitle->centerMenuOnScreen(); // Inicializa el objeto con el menu de pausa menuPause = new Menu(gRenderer); menuPause->init(0, 12 * BLOCK, MENU_SELECTOR_WHITE, MENU_BACKGROUND_SOLID); menuPause->addItem("CONTINUE"); menuPause->addItem("EXIT TO TITLE"); menuPause->setBackgroundColor(0x73, 0x27, 0x5c, 255); menuPause->centerMenuOnScreen(); } // Hace una pausa de milisegundos void GameDirector::sleep(Uint16 time) { Uint32 ticks = SDL_GetTicks(); while (SDL_GetTicks() - ticks < time) { /* code */ } } // Establece el valor de la variable void GameDirector::setScore(Uint32 score) { mScore = score; } // Establece el valor de la variable void GameDirector::setHiScore(Uint32 score) { mHiScore = score; } // Actualiza el valor de HiScore en caso necesario void GameDirector::updateHiScore() { if (mScore > mHiScore) { mHiScore = mScore; } } // Transforma un valor numérico en una cadena de 6 cifras std::string GameDirector::updateScoreText(Uint32 num) { switch (num) { case 0 ... 9: return ("00000" + std::to_string(num)); break; case 10 ... 99: return ("0000" + std::to_string(num)); break; case 100 ... 999: return ("000" + std::to_string(num)); break; case 1000 ... 9999: return ("00" + std::to_string(num)); break; case 10000 ... 99999: return ("0" + std::to_string(num)); break; case 100000 ... 999999: return (std::to_string(num)); break; default: return (std::to_string(num)); break; } } // Pinta el marcador en pantalla usando un objeto texto void GameDirector::renderScoreBoard(Text &text) { mScoreText = updateScoreText(mScore); mHiScoreText = updateScoreText(mHiScore); text.write(SCORE_WORD_X, SCORE_WORD_Y, "SCORE"); text.write(SCORE_NUMBER_X, SCORE_NUMBER_Y, mScoreText); text.write(HISCORE_WORD_X, HISCORE_WORD_Y, "HI-SCORE"); text.write(HISCORE_NUMBER_X, HISCORE_NUMBER_Y, mHiScoreText); } // Mueve todos los globos activos void GameDirector::moveBalloons() { for (Uint8 i = 0; i < mMaxBalloons; i++) { if (balloon[i]->isActive()) { balloon[i]->move(); } } } // Pinta en pantalla todos los globos activos void GameDirector::renderBalloons() { for (Uint8 i = 0; i < mMaxBalloons; i++) { if (balloon[i]->isActive()) { balloon[i]->render(); } } } // Devuelve el primer indice no activo del vector de globos Uint8 GameDirector::getBallonFreeIndex() { int index = 0; for (Uint8 i = 0; i < mMaxBalloons; i++) { if (balloon[i]->isActive() == false) { index = i; break; } } return index; } // Crea un globo nuevo en el vector de globos Uint8 GameDirector::createNewBalloon(int x, int y, Uint8 kind, float velx, Uint16 creationtimer) { const Uint8 index = getBallonFreeIndex(); balloon[index]->init(x, y, kind, velx, creationtimer); return index; } // Establece a cero todos los valores del vector de objetos globo void GameDirector::resetBalloons() { for (Uint8 i = 0; i < mMaxBalloons; i++) { balloon[i]->erase(); } } // Explosiona un globo. Lo destruye y crea otros dos si es el caso void GameDirector::popBalloon(Uint8 index) { if (balloon[index]->isActive()) { Uint8 kind = balloon[index]->getKind(); Uint8 freeIndex = 0; switch (kind) { // Si es del tipo más pequeño, simplemente elimina el globo case BALLOON_1: balloon[index]->erase(); break; // En cualquier otro caso, crea dos globos de un tipo inferior default: freeIndex = getBallonFreeIndex(); balloon[freeIndex]->init(0, balloon[index]->getPosY(), balloon[index]->getKind() - 1, BALLON_VELX_NEGATIVE, 0); balloon[freeIndex]->allignTo(balloon[index]->getPosX() + (balloon[index]->getWidth() / 2)); balloon[freeIndex]->setVelY(-2.5); freeIndex = getBallonFreeIndex(); balloon[freeIndex]->init(0, balloon[index]->getPosY(), balloon[index]->getKind() - 1, BALLON_VELX_POSITIVE, 0); balloon[freeIndex]->allignTo(balloon[index]->getPosX() + (balloon[index]->getWidth() / 2)); balloon[freeIndex]->setVelY(-2.5); // Elimina el globo balloon[index]->erase(); break; } } } // Detiene todos los globos void GameDirector::stopAllBalloons() { for (Uint8 i = 0; i < mMaxBalloons; i++) { if (balloon[i]->isActive()) { balloon[i]->setStop(true); } } } // Pone en marcha todos los globos void GameDirector::startAllBalloons() { for (Uint8 i = 0; i < mMaxBalloons; i++) { if (balloon[i]->isActive()) { balloon[i]->setStop(false); } } } // Obtiene el numero de globos activos Uint8 GameDirector::countBalloons() { Uint8 num = 0; for (Uint8 i = 0; i < mMaxBalloons; i++) { if (balloon[i]->isActive()) { ++num; } } return num; } // Comprueba la colisión entre el jugador y los globos activos bool GameDirector::checkPlayerBallonCollision() { bool result = false; for (Uint8 i = 0; i < mMaxBalloons; i++) { if (balloon[i]->isActive()) { if (checkCollision(player->getCollider(), balloon[i]->getCollider())) { result = true; break; } } } return result; } // Comprueba y procesa la colisión entre las balas y los globos void GameDirector::processBulletBallonCollision() { for (Uint8 i = 0; i < mMaxBalloons; i++) { for (Uint8 j = 0; j < mMaxBullets; j++) { if (balloon[i]->isActive() && !(balloon[i]->isInvulnerable()) && bullet[j]->isActive()) { if (checkCollision(balloon[i]->getCollider(), bullet[j]->getCollider())) { player->addScore(balloon[i]->getScore()); setScore(player->getScore()); updateHiScore(); popBalloon(i); Mix_PlayChannel(-1, gPopBalloonFX, 0); bullet[j]->erase(); calculateMenaceLevel(); break; } } } } } // Mueve las balas activas void GameDirector::moveBullets() { for (Uint8 i = 0; i < mMaxBullets; i++) { if (bullet[i]->isActive()) { bullet[i]->move(); } } } // Pinta las balas activas void GameDirector::renderBullets() { for (Uint8 i = 0; i < mMaxBullets; i++) { if (bullet[i]->isActive()) { bullet[i]->render(); } } } // Devuelve el primer indice no activo del vector de balas Uint8 GameDirector::getBulletFreeIndex() { Uint8 index = 0; for (int i = 0; i < mMaxBullets; i++) { if (bullet[i]->isActive() == false) { index = i; break; } } return index; } // Establece a cero todos los valores del vector de objetos bala void GameDirector::resetBullets() { for (Uint8 i = 0; i < mMaxBullets; i++) { bullet[i]->init(0, 0, NO_KIND); } } // Crea un objeto bala void GameDirector::createBullet(int x, int y, Uint8 kind) { const int index = getBulletFreeIndex(); bullet[index]->init(x, y, kind); } // Calcula y establece el valor de amenaza en funcion de los globos activos void GameDirector::calculateMenaceLevel() { mMenaceLevel = 0; for (Uint8 i = 0; i < mMaxBalloons; i++) { switch (balloon[i]->getKind()) { case BALLOON_1: mMenaceLevel += 1; break; case BALLOON_2: mMenaceLevel += 2; break; case BALLOON_3: mMenaceLevel += 4; break; case BALLOON_4: mMenaceLevel += 8; break; default: mMenaceLevel += 0; break; } } } // Obtiene el valor de la variable Uint8 GameDirector::getMenaceLevel() { return mMenaceLevel; } // Gestiona el nivel de amenaza void GameDirector::checkMenaceLevel() { // Aumenta el nivel de amenaza en función de la puntuación mMenaceLevelThreshold = 7 + (4 * (mScore / 10000)); // Si el nivel de amenza es inferior al umbral if (mMenaceLevel < mMenaceLevelThreshold) { Uint8 index = 0; // Obtiene el centro del jugador en el eje X int x = player->getPosX() + (player->getWidth() / 2); // Crea un globo sobre el jugador en dirección hacia el centro if (x < (PLAY_AREA_WIDTH / 2)) { index = createNewBalloon(0, PLAY_AREA_TOP + BLOCK - 37, BALLOON_4, BALLON_VELX_POSITIVE, 400); } else { index = createNewBalloon(0, PLAY_AREA_TOP + BLOCK - 37, BALLOON_4, BALLON_VELX_NEGATIVE, 400); } balloon[index]->allignTo(x); // Recalcula el nivel de amenaza con el nuevo globo calculateMenaceLevel(); } } // Gestiona la entrada de teclado y mando durante el juego void GameDirector::checkGameInput() { // Obtiene el estado de las teclas pulsadas del teclado const Uint8 *keystates = SDL_GetKeyboardState(NULL); // Si está pulsada la tecla izquierda o el mando hacia la izquierda if ((keystates[SDL_SCANCODE_LEFT] != 0) || (SDL_JoystickGetAxis(gGameController, 0) < -JOYSTICK_DEAD_ZONE)) { player->checkInput(INPUT_LEFT); } // Si está pulsada la tecla derecha o el mando hacia la derecha else if ((keystates[SDL_SCANCODE_RIGHT] != 0) || (SDL_JoystickGetAxis(gGameController, 0) > JOYSTICK_DEAD_ZONE)) { player->checkInput(INPUT_RIGHT); } // Ninguna de las dos direcciones pulsadas else { player->checkInput(NO_INPUT); } // Comprobamos la tecla o el botón de disparo central if ((SDL_JoystickGetButton(gGameController, BUTTON_X)) || (keystates[SDL_SCANCODE_W] != 0)) { if (player->canFire()) { createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY(), BULLET_UP); player->setFireCooldown(10); // Reproduce el sonido de disparo Mix_PlayChannel(-1, gBulletFX, 0); } } // Comprobamos la tecla o el botón de disparo izquierdo if ((SDL_JoystickGetButton(gGameController, BUTTON_Y)) || (keystates[SDL_SCANCODE_Q] != 0)) { if (player->canFire()) { createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY(), BULLET_LEFT); player->setFireCooldown(10); // Reproduce el sonido de disparo Mix_PlayChannel(-1, gBulletFX, 0); } } // Comprobamos la tecla o el botón de disparo derecho if ((SDL_JoystickGetButton(gGameController, BUTTON_A)) || (keystates[SDL_SCANCODE_E] != 0)) { if (player->canFire()) { createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY(), BULLET_RIGHT); player->setFireCooldown(10); // Reproduce el sonido de disparo Mix_PlayChannel(-1, gBulletFX, 0); } } // Comprobamos la tecla o el botón de pausa/menu if ((SDL_JoystickGetButton(gGameController, BUTTON_START)) || (keystates[SDL_SCANCODE_ESCAPE] != 0)) { setGameStatus(GAME_STATE_PAUSED); // Detiene la música Mix_HaltMusic(); } } // Gestiona la entrada de teclado y mando durante el menu void GameDirector::checkMenuInput(Menu *menu) { // Obtiene el estado de las teclas pulsadas del teclado const Uint8 *keystates = SDL_GetKeyboardState(NULL); // Si está pulsada la tecla izquierda o el mando hacia la izquierda if ((keystates[SDL_SCANCODE_UP] != 0) || (SDL_JoystickGetAxis(gGameController, 1) < -JOYSTICK_DEAD_ZONE)) { menu->checkInput(INPUT_UP); } // Si está pulsada la tecla derecha o el mando hacia la derecha else if ((keystates[SDL_SCANCODE_DOWN] != 0) || (SDL_JoystickGetAxis(gGameController, 1) > JOYSTICK_DEAD_ZONE)) { menu->checkInput(INPUT_DOWN); } // Comprobamos la tecla o el botón de menu/pausa else if (keystates[SDL_SCANCODE_RETURN] != 0 || (SDL_JoystickGetButton(gGameController, BUTTON_A))) { menu->checkInput(INPUT_FIRE); } #ifdef TEST if (SDL_JoystickGetButton(gGameController, 1)) { std::cout << "button1\n"; } if (SDL_JoystickGetButton(gGameController, 1)) { std::cout << "button1\n"; } if (SDL_JoystickGetButton(gGameController, 2)) { std::cout << "button2\n"; } if (SDL_JoystickGetButton(gGameController, 3)) { std::cout << "button3\n"; } if (SDL_JoystickGetButton(gGameController, 4)) { std::cout << "button4\n"; } if (SDL_JoystickGetButton(gGameController, 5)) { std::cout << "button5\n"; } if (SDL_JoystickGetButton(gGameController, 6)) { std::cout << "button6\n"; } if (SDL_JoystickGetButton(gGameController, 7)) { std::cout << "button7\n"; } if (SDL_JoystickGetButton(gGameController, 8)) { std::cout << "button8\n"; } if (SDL_JoystickGetButton(gGameController, 9)) { std::cout << "button9\n"; } if (SDL_JoystickGetButton(gGameController, 10)) { std::cout << "button10\n"; } if (SDL_JoystickGetButton(gGameController, 11)) { std::cout << "button11\n"; } if (SDL_JoystickGetButton(gGameController, 12)) { std::cout << "button12\n"; } if (SDL_JoystickGetButton(gGameController, 13)) { std::cout << "button13\n"; } if (SDL_JoystickGetButton(gGameController, 14)) { std::cout << "button14\n"; } if (SDL_JoystickGetButton(gGameController, 15)) { std::cout << "button15\n"; } #endif } // Obtiene el valor de la variable Uint8 GameDirector::getGameStatus() { return mGameStatus; } // Establece el valor de la variable void GameDirector::setGameStatus(Uint8 status) { mGameStatus = status; } // Pinta una transición en pantalla void GameDirector::renderTransition(Uint8 index) { switch (index) { case 0: SDL_Rect rect; rect.x = 0; rect.y = 0; rect.w = SCREEN_WIDTH; rect.h = 0; SDL_RenderPresent(gRenderer); SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 0); for (Uint16 i = 0; i < SCREEN_HEIGHT; i = i + 2) { rect.h = i; SDL_RenderFillRect(gRenderer, &rect); SDL_RenderPresent(gRenderer); } break; case 1: SDL_Rect rect1; rect1.x = 0; rect1.y = 0; rect1.w = SCREEN_WIDTH; rect1.h = 0; SDL_Rect rect2; rect2.x = 0; rect2.y = 0; rect2.w = SCREEN_WIDTH; rect2.h = 0; SDL_RenderPresent(gRenderer); SDL_SetRenderDrawBlendMode(gRenderer, SDL_BLENDMODE_BLEND); SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 64); for (Uint16 i = 0; i < (SCREEN_HEIGHT / 2); i = i + 4) { rect1.h = i; SDL_RenderFillRect(gRenderer, &rect1); rect2.h = i; rect2.y = SCREEN_HEIGHT - (i); SDL_RenderFillRect(gRenderer, &rect2); SDL_RenderPresent(gRenderer); } rect1.x = 0; rect1.y = 0; rect1.w = SCREEN_WIDTH; rect1.h = SCREEN_HEIGHT; for (Uint16 i = 0; i < (SCREEN_HEIGHT / 2); i = i + 4) { SDL_RenderFillRect(gRenderer, &rect1); SDL_RenderPresent(gRenderer); } break; default: break; } } // Pinta el texto GetReady en pantalla void GameDirector::renderGetReady() { if (mGetReady) { Sprite sprite; sprite.setTexture(*gMiscTexture); sprite.setWidth(53); sprite.setHeight(10); sprite.setPosX((PLAY_AREA_WIDTH / 2) - (sprite.getWidth() / 2)); sprite.setPosY((PLAY_AREA_HEIGHT / 2) - (sprite.getHeight() / 2)); sprite.setSpriteClip(0, 0, sprite.getWidth(), sprite.getHeight()); for (Uint8 i = 0; i < 1; i++) { sprite.render(); SDL_RenderPresent(gRenderer); SDL_Delay(1500); } mGetReady = false; } } // Bucle para el titulo del juego void GameDirector::runTitle() { // Si la música no está sonando if (Mix_PlayingMusic() == 0) { // Reproduce la música Mix_PlayMusic(gTitleMusic, -1); } // 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) { setGameStatus(GAME_STATE_QUIT); } } // Limpia la pantalla SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0xFF); SDL_RenderClear(gRenderer); // Dibuja los objetos titleBackground.render(); menuTitle->render(whiteText); // Actualiza la pantalla SDL_RenderPresent(gRenderer); // Comprueba las entradas para el menu checkMenuInput(menuTitle); // Comprueba si se ha seleccionado algún item del menú switch (menuTitle->getItemSelected()) { case 0: setGameStatus(GAME_STATE_PLAYING); menuTitle->resetMenu(); renderTransition(1); Mix_HaltMusic(); SDL_Delay(1200); break; case 1: setGameStatus(GAME_STATE_QUIT); menuTitle->resetMenu(); renderTransition(1); Mix_HaltMusic(); break; default: break; } } // Bucle para el juego void GameDirector::runGame() { // Si la música no está sonando if (Mix_PlayingMusic() == 0) { // Reproduce la música Mix_PlayMusic(gPlayingMusic, -1); } // Lógica del juego // Comprueba que la diferencia de ticks sea mayor a la velocidad del juego if (SDL_GetTicks() - mOldTicks > mGameSpeed) { // Actualiza el contador de ticks mOldTicks = SDL_GetTicks(); // Comprueba el teclado/mando checkGameInput(); // 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) { setGameStatus(GAME_STATE_QUIT); } // Tecla T pulsada if (eventHandler.key.keysym.sym == SDLK_t) { // startAllBalloons(); popBalloon(0); break; } #ifdef TEST // W key pressed if (eventHandler.key.keysym.sym == SDLK_w) { bulletTest.setPosY(bulletTest.getPosY() - 1); bulletTest.testMove(); break; } // S key pressed if (eventHandler.key.keysym.sym == SDLK_s) { bulletTest.setPosY(bulletTest.getPosY() + 1); bulletTest.testMove(); break; } // A key pressed if (eventHandler.key.keysym.sym == SDLK_a) { bulletTest.setPosX(bulletTest.getPosX() - 1); bulletTest.testMove(); break; } // D key pressed if (eventHandler.key.keysym.sym == SDLK_d) { bulletTest.setPosX(bulletTest.getPosX() + 1); bulletTest.testMove(); break; } #endif } // Actualiza el jugador player->update(); // Mueve los globos moveBalloons(); #ifdef TEST balloonTest.move(); #endif // Mueve las balas moveBullets(); // Procesa las colisiones entre globos y balas processBulletBallonCollision(); // Comprueba el nivel de amenaza checkMenaceLevel(); // Comprueba la colisión entre el jugador y los globos if (checkPlayerBallonCollision()) { // stopAllBalloons(); } } // Limpia la pantalla SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0xFF); SDL_RenderClear(gRenderer); // Dibuja los objetos gameBackground.render(); renderBalloons(); #ifdef TEST balloonTest.render(); bulletTest.render(); if (checkCollision(balloonTest.getCollider(), bulletTest.getCollider())) { whiteText.write(0, 0, "X"); } #endif // whiteText.write(0, 0, std::to_string(mMenaceLevelThreshold)); // whiteText.write(0, BLOCK, std::to_string(player->getPosX() + player->getWidth())); renderBullets(); player->render(); renderScoreBoard(whiteText); renderGetReady(); // Actualiza la pantalla SDL_RenderPresent(gRenderer); } // Bucle para el menu de pausa del juego void GameDirector::runPausedGame() { // 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) { setGameStatus(GAME_STATE_QUIT); } } // Dibuja los objetos gameBackground.render(); renderBalloons(); renderBullets(); player->render(); renderScoreBoard(whiteText); menuPause->render(whiteText); // Limpia la pantalla SDL_RenderPresent(gRenderer); // Comprueba las entradas para el menu checkMenuInput(menuPause); // Comprueba si se ha seleccionado algún item del menú switch (menuPause->getItemSelected()) { case 0: setGameStatus(GAME_STATE_PLAYING); menuPause->resetMenu(); break; case 1: setGameStatus(GAME_STATE_TITLE); menuPause->resetMenu(); renderTransition(1); init(); break; default: break; } }