diff --git a/data/gfx/menu_game_over_end.png b/data/gfx/menu_game_over_end.png new file mode 100644 index 0000000..5e8fe65 Binary files /dev/null and b/data/gfx/menu_game_over_end.png differ diff --git a/source/director.cpp b/source/director.cpp index aefc980..a45eaf1 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -11,6 +11,9 @@ Director::Director(std::string path) section.name = PROG_SECTION_GAME; section.subsection = GAME_SECTION_PLAY_1P; + section.name = PROG_SECTION_TITLE; + section.subsection = TITLE_SECTION_1; + // Crea el objeto que controla los ficheros de recursos asset = new Asset(path.substr(0, path.find_last_of("\\/")) + "/../"); @@ -213,6 +216,7 @@ bool Director::setFileList() asset->add("data/gfx/intro.png", t_bitmap); asset->add("data/gfx/logo.png", t_bitmap); asset->add("data/gfx/menu_game_over.png", t_bitmap); + asset->add("data/gfx/menu_game_over_end.png", t_bitmap); asset->add("data/gfx/item_points1_disk.png", t_bitmap); asset->add("data/gfx/item_points1_disk.ani", t_data); diff --git a/source/game.cpp b/source/game.cpp index 0ce70b3..e4ca9f5 100644 --- a/source/game.cpp +++ b/source/game.cpp @@ -14,7 +14,7 @@ Game::Game(int numPlayers, int currentStage, SDL_Renderer *renderer, Screen *scr // Pasa variables this->demo.enabled = demo; this->numPlayers = numPlayers; - this->currentStage = currentStage; + this->currentStage = 9; // currentStage; lastStageReached = currentStage; if (numPlayers == 1) { // Si solo juega un jugador, permite jugar tanto con teclado como con mando @@ -45,6 +45,7 @@ Game::Game(int numPlayers, int currentStage, SDL_Renderer *renderer, Screen *scr grassSprite = new Sprite(0, 0, 256, 6, gameGrassTexture, renderer); powerMeterSprite = new Sprite(PLAY_AREA_CENTER_X - 20, 170, 40, 7, gamePowerMeterTexture, renderer); gameOverSprite = new Sprite(16, 80, 128, 96, gameOverTexture, renderer); + gameOverEndSprite = new Sprite(PLAY_AREA_CENTER_X - gameOverEndTexture->getWidth() / 2, 80, 128, 96, gameOverEndTexture, renderer); // Inicializa las variables necesarias para la sección 'Game' init(); @@ -88,6 +89,9 @@ Game::~Game() gameOverTexture->unload(); delete gameOverTexture; + gameOverEndTexture->unload(); + delete gameOverEndTexture; + // Animaciones for (auto animation : playerAnimations) { @@ -157,6 +161,8 @@ Game::~Game() delete skyColorsSprite; delete grassSprite; delete powerMeterSprite; + delete gameOverSprite; + delete gameOverEndSprite; JA_DeleteSound(balloonSound); JA_DeleteSound(bulletSound); @@ -183,13 +189,14 @@ void Game::init() ticks = 0; ticksSpeed = 15; - // Crea los jugadores + // Elimina qualquier jugador que hubiese antes de crear los nuevos for (auto player : players) { delete player; }; players.clear(); + // Crea los jugadores if (numPlayers == 1) { Player *player = new Player(PLAY_AREA_CENTER_X - 11, PLAY_AREA_BOTTOM - 24, renderer, player1Textures, playerAnimations); @@ -212,7 +219,6 @@ void Game::init() difficultyScoreMultiplier = 0.5f; difficultyColor = {75, 105, 47}; pauseMenu->setSelectorColor(difficultyColor, 255); - // gameOverMenu->setSelectorTextColor(difficultyColor); gameOverMenu->setSelectorColor(difficultyColor, 255); break; @@ -221,7 +227,6 @@ void Game::init() difficultyScoreMultiplier = 1.0f; difficultyColor = {255, 122, 0}; pauseMenu->setSelectorColor(difficultyColor, 255); - // gameOverMenu->setSelectorTextColor(difficultyColor); gameOverMenu->setSelectorColor(difficultyColor, 255); break; @@ -230,13 +235,13 @@ void Game::init() difficultyScoreMultiplier = 1.5f; difficultyColor = {118, 66, 138}; pauseMenu->setSelectorColor(difficultyColor, 255); - // gameOverMenu->setSelectorTextColor(difficultyColor); gameOverMenu->setSelectorColor(difficultyColor, 255); break; default: break; } + gameCompleted = false; gameCompletedCounter = 0; section.name = PROG_SECTION_GAME; @@ -302,6 +307,9 @@ void Game::init() totalPowerToCompleteGame += stage[i].powerToComplete; } + balloonsPopped = totalPowerToCompleteGame - 20; + stage[9].currentPower = stage[9].powerToComplete - 20; + // Modo demo demo.recording = false; demo.counter = 0; @@ -392,6 +400,7 @@ void Game::loadMedia() gameSkyColorsTexture = new LTexture(renderer, asset->get("game_sky_colors.png")); gameTextTexture = new LTexture(renderer, asset->get("game_text.png")); gameOverTexture = new LTexture(renderer, asset->get("menu_game_over.png")); + gameOverEndTexture = new LTexture(renderer, asset->get("menu_game_over_end.png")); // Texturas - Globos LTexture *balloon1Texture = new LTexture(renderer, asset->get("balloon1.png")); @@ -455,7 +464,7 @@ void Game::loadMedia() player2Textures.push_back(player2Death); LTexture *player2Fire = new LTexture(renderer, asset->get("player_arounder_fire.png")); - player1Textures.push_back(player2Fire); + player2Textures.push_back(player2Fire); // Animaciones -- Jugador std::vector *playerHeadAnimation = new std::vector; @@ -1706,8 +1715,7 @@ void Game::updateStage() stage[currentStage].currentPower = 0; // Vuelve a dejar el poder a cero, por lo que hubiera podido subir al destruir todos lo globos menaceCurrent = 255; // Sube el nivel de amenaza para que no cree mas globos for (auto player : players) - // for (int i = 0; i < numPlayers; i++) // Añade un millon de puntos a los jugadores que queden vivos - { + { // Añade un millon de puntos a los jugadores que queden vivos if (player->isAlive()) { player->addScore(1000000); @@ -2755,18 +2763,38 @@ void Game::update() // Actualiza el fondo void Game::updateBackground() { - const float speed = (-0.2f) + (-3.00f * ((float)balloonsPopped / (float)totalPowerToCompleteGame)); + if (!gameCompleted) + { // Si el juego no esta completo, la velocidad de las nubes es igual a los globos explotados + cloudsSpeed = balloonsPopped; + } + else + { // Si el juego está completado, se reduce la velocidad de las nubes + if (cloudsSpeed > 400) + { + cloudsSpeed -= 25; + } + else + { + cloudsSpeed = 200; + } + } + // Calcula la velocidad en función de los globos explotados y el total de globos a explotar para acabar el juego + const float speed = (-0.2f) + (-3.00f * ((float)cloudsSpeed / (float)totalPowerToCompleteGame)); + + // Aplica la velocidad calculada a las nubes clouds1A->setVelX(speed); clouds1B->setVelX(speed); clouds2A->setVelX(speed / 2); clouds2B->setVelX(speed / 2); + // Mueve las nubes clouds1A->move(); clouds1B->move(); clouds2A->move(); clouds2B->move(); + // Calcula el offset de las nubes if (clouds1A->getPosX() < -clouds1A->getWidth()) { clouds1A->setPosX(clouds1A->getWidth()); @@ -2787,8 +2815,10 @@ void Game::updateBackground() clouds2B->setPosX(clouds2B->getWidth()); } + // Calcula el frame de la hierba grassSprite->setSpriteClip(0, (6 * (counter / 20 % 2)), 256, 6); + // Mueve los edificios en funcion de si está activo el efecto de agitarlos if (effect.shake) { buildingsSprite->setPosX(((effect.shakeCounter % 2) * 2) - 1); @@ -2853,16 +2883,13 @@ void Game::render() renderDeathFade(150 - deathCounter); } - if ((gameCompleted) && (gameCompletedCounter >= 300)) + if ((gameCompleted) && (gameCompletedCounter >= GAME_COMPLETED_START_FADE)) { - renderDeathFade(gameCompletedCounter - 300); + renderDeathFade(gameCompletedCounter - GAME_COMPLETED_START_FADE); } renderFlashEffect(); - const std::string txt = std::to_string(balloonsPopped) + "-" + std::to_string(totalPowerToCompleteGame); - text->write(0, 0, txt); - // Vuelca el contenido del renderizador en pantalla screen->blit(); } @@ -3297,9 +3324,9 @@ void Game::runPausedGame() renderDeathFade(150 - deathCounter); } - if ((gameCompleted) && (gameCompletedCounter >= 300)) + if ((gameCompleted) && (gameCompletedCounter >= GAME_COMPLETED_START_FADE)) { - renderDeathFade(gameCompletedCounter - 300); + renderDeathFade(gameCompletedCounter - GAME_COMPLETED_START_FADE); } renderFlashEffect(); @@ -3385,10 +3412,18 @@ void Game::runGameOverScreen() switch (postFade) { case 0: // YES - section.name = PROG_SECTION_GAME; - deleteAllVectorObjects(); - init(); - section.subsection = numPlayers == 1 ? GAME_SECTION_PLAY_1P : GAME_SECTION_PLAY_2P; + if (!gameCompleted) + { // Si el juego no se ha terminado, el menu actua normal + section.name = PROG_SECTION_GAME; + deleteAllVectorObjects(); + init(); + section.subsection = numPlayers == 1 ? GAME_SECTION_PLAY_1P : GAME_SECTION_PLAY_2P; + } + else + { // Si ha completado el juego, siempre vuelve a la pantalla de titulo + section.name = PROG_SECTION_TITLE; + section.subsection = TITLE_SECTION_1; + } break; case 1: // NO @@ -3411,29 +3446,44 @@ void Game::runGameOverScreen() screen->clean(bgColor); // Dibujo - gameOverSprite->render(); + if (!gameCompleted) + { // Dibujo de haber perdido la partida + gameOverSprite->render(); + } + else + { // Dinujo de haber completado la partida + gameOverEndSprite->render(); + } // Dibuja los objetos if (numPlayers == 1) { // Game Over textBig->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 6), lang->getText(43)); - // textBig->writeDX(TXT_CENTER | TXT_SHADOW, PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 6), lang->getText(43), 1, {255, 255, 235}, 1, difficultyColor); // Your Score text->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 3), lang->getText(44) + std::to_string(players.at(0)->getScore())); - // text->writeDX(TXT_CENTER | TXT_SHADOW, PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 3), lang->getText(44) + std::to_string(players.at(0)->getScore()), 1, {255, 255, 235}, 1, difficultyColor); } else { - textBig->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - 36, lang->getText(43)); - text->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - 12, lang->getText(77) + std::to_string(players.at(0)->getScore())); - text->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y, lang->getText(78) + std::to_string(players.at(1)->getScore())); + // Game Over + textBig->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 7), lang->getText(43)); + + // Player1 Score + text->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 4), lang->getText(77) + std::to_string(players.at(0)->getScore())); + + // Player2 Score + text->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 2), lang->getText(78) + std::to_string(players.at(1)->getScore())); } + // Continue? - text->writeCentered(199, PLAY_AREA_CENTER_Y + BLOCK * 3, lang->getText(45)); - // text->writeDX(TXT_CENTER | TXT_SHADOW, 199, PLAY_AREA_CENTER_Y + BLOCK * 3, lang->getText(45), 1, {255, 255, 235}, 1, difficultyColor); - gameOverMenu->render(); + if (!gameCompleted) + { // Solo dibuja el menu de continuar en el caso de no haber completado la partida + text->writeCentered(199, PLAY_AREA_CENTER_Y + BLOCK * 3, lang->getText(45)); + gameOverMenu->render(); + } + + // Pinta el fade fade->render(); // Vuelca el contenido del renderizador en pantalla @@ -3563,7 +3613,7 @@ void Game::updateGameCompleted() gameCompletedCounter++; } - if (gameCompletedCounter == 500) + if (gameCompletedCounter == GAME_COMPLETED_END) { section.subsection = GAME_SECTION_GAMEOVER; } diff --git a/source/game.h b/source/game.h index 4addfd8..41deb79 100644 --- a/source/game.h +++ b/source/game.h @@ -31,6 +31,8 @@ #define STAGE_COUNTER 200 #define SHAKE_COUNTER 10 #define HELP_COUNTER 1000 +#define GAME_COMPLETED_START_FADE 500 +#define GAME_COMPLETED_END 700 // Formaciones enemigas #define NUMBER_OF_ENEMY_FORMATIONS 100 @@ -138,6 +140,7 @@ private: LTexture *gameSkyColorsTexture; // Textura con los diferentes colores de fondo del juego LTexture *gameTextTexture; // Textura para los sprites con textos LTexture *gameOverTexture; // Textura para la pantalla de game over + LTexture *gameOverEndTexture; // Textura para la pantalla de game over de acabar el juego std::vector *> itemAnimations; // Vector con las animaciones de los items std::vector *> playerAnimations; // Vector con las animaciones del jugador @@ -163,11 +166,12 @@ private: SmartSprite *n2500Sprite; // Sprite con el texto 2.500 SmartSprite *n5000Sprite; // Sprite con el texto 5.000 - Sprite *buildingsSprite; // Sprite con los edificios de fondo - Sprite *skyColorsSprite; // Sprite con los graficos del degradado de color de fondo - Sprite *grassSprite; // Sprite para la hierba - Sprite *powerMeterSprite; // Sprite para el medidor de poder de la fase - Sprite *gameOverSprite; // Sprite para dibujar los graficos del game over + Sprite *buildingsSprite; // Sprite con los edificios de fondo + Sprite *skyColorsSprite; // Sprite con los graficos del degradado de color de fondo + Sprite *grassSprite; // Sprite para la hierba + Sprite *powerMeterSprite; // Sprite para el medidor de poder de la fase + Sprite *gameOverSprite; // Sprite para dibujar los graficos del game over + Sprite *gameOverEndSprite; // Sprite para dibujar los graficos del game over de acabar el juego JA_Sound balloonSound; // Sonido para la explosión del globo JA_Sound bulletSound; // Sonido para los disparos @@ -230,6 +234,7 @@ private: Uint8 lastStageReached; // Contiene el numero de la última pantalla que se ha alcanzado demo_t demo; // Variable con todas las variables relacionadas con el modo demo int totalPowerToCompleteGame; // La suma del poder necesario para completar todas las fases + int cloudsSpeed; // Velocidad a la que se desplazan las nubes // Actualiza el juego void update(); diff --git a/todo.txt b/todo.txt index ec29b2f..bb42cd1 100644 --- a/todo.txt +++ b/todo.txt @@ -21,5 +21,8 @@ NO que grite "yiiijaa!" o algo parecido al coger la maquina de cafe NO o que diga DIMONIS! en un globo de texto que se evapore NO podrian salir comentarios aleatoriamente o con ciertos eventos (falta ver si no estorbará) x que se vea el nivel de dificultad -poner un dibujito en la pantalla de game over al terminar el juego -x y quizas otro en la propia pantalla de game over \ No newline at end of file +x poner un dibujito en la pantalla de game over al terminar el juego +x y quizas otro en la propia pantalla de game over +x que las nubes al final se vuelva a frenar +quitar las cabezas powerup +x el modo 2P no arranca \ No newline at end of file