From 943fb7bf2742cbeb3432ba86540a55b7bb21bc26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Valor=20Mart=C3=ADnez?= Date: Sun, 22 Aug 2021 19:50:55 +0200 Subject: [PATCH] working on 2players --- source/director.cpp | 59 +++-- source/director.h | 3 +- source/game.cpp | 525 ++++++++++++++++++++++++-------------------- source/game.h | 33 +-- source/title.cpp | 2 +- 5 files changed, 350 insertions(+), 272 deletions(-) diff --git a/source/director.cpp b/source/director.cpp index dfecdf7..1c8ae7a 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -11,7 +11,8 @@ Director::Director(std::string path) { // Crea los objetos - mInput = new Input(); + mInput1 = new Input(); + mInput2 = new Input(); mOptions = new options_t; // Inicializa variables @@ -45,8 +46,10 @@ Director::~Director() { saveConfigFile(); - delete mInput; - mInput = nullptr; + delete mInput1; + mInput1 = nullptr; + delete mInput2; + mInput2 = nullptr; delete mOptions; mOptions = nullptr; @@ -78,23 +81,41 @@ void Director::init() initTextStrings(mTextStrings, mOptions->language); // Teclado - mInput->bindKey(INPUT_UP, SDL_SCANCODE_UP); - mInput->bindKey(INPUT_DOWN, SDL_SCANCODE_DOWN); - mInput->bindKey(INPUT_LEFT, SDL_SCANCODE_LEFT); - mInput->bindKey(INPUT_RIGHT, SDL_SCANCODE_RIGHT); - mInput->bindKey(INPUT_ACCEPT, SDL_SCANCODE_RETURN); - mInput->bindKey(INPUT_CANCEL, SDL_SCANCODE_ESCAPE); + mInput1->bindKey(INPUT_UP, SDL_SCANCODE_UP); + mInput1->bindKey(INPUT_DOWN, SDL_SCANCODE_DOWN); + mInput1->bindKey(INPUT_LEFT, SDL_SCANCODE_LEFT); + mInput1->bindKey(INPUT_RIGHT, SDL_SCANCODE_RIGHT); + mInput1->bindKey(INPUT_ACCEPT, SDL_SCANCODE_RETURN); + mInput1->bindKey(INPUT_CANCEL, SDL_SCANCODE_ESCAPE); #ifdef __MIPSEL__ - mInput->bindKey(INPUT_BUTTON_1, SDL_SCANCODE_LSHIFT); - mInput->bindKey(INPUT_BUTTON_2, SDL_SCANCODE_SPACE); - mInput->bindKey(INPUT_BUTTON_3, SDL_SCANCODE_LCTRL); + mInput1->bindKey(INPUT_BUTTON_1, SDL_SCANCODE_LSHIFT); + mInput1->bindKey(INPUT_BUTTON_2, SDL_SCANCODE_SPACE); + mInput1->bindKey(INPUT_BUTTON_3, SDL_SCANCODE_LCTRL); #else - mInput->bindKey(INPUT_BUTTON_1, SDL_SCANCODE_Q); - mInput->bindKey(INPUT_BUTTON_2, SDL_SCANCODE_W); - mInput->bindKey(INPUT_BUTTON_3, SDL_SCANCODE_E); + mInput1->bindKey(INPUT_BUTTON_1, SDL_SCANCODE_Q); + mInput1->bindKey(INPUT_BUTTON_2, SDL_SCANCODE_W); + mInput1->bindKey(INPUT_BUTTON_3, SDL_SCANCODE_E); #endif - mInput->bindKey(INPUT_BUTTON_4, SDL_SCANCODE_ESCAPE); // PAUSE - mInput->bindKey(INPUT_BUTTON_5, SDL_SCANCODE_ESCAPE); // ESCAPE + mInput1->bindKey(INPUT_BUTTON_4, SDL_SCANCODE_ESCAPE); // PAUSE + mInput1->bindKey(INPUT_BUTTON_5, SDL_SCANCODE_ESCAPE); // ESCAPE + + mInput2->bindKey(INPUT_UP, SDL_SCANCODE_UP); + mInput2->bindKey(INPUT_DOWN, SDL_SCANCODE_DOWN); + mInput2->bindKey(INPUT_LEFT, SDL_SCANCODE_LEFT); + mInput2->bindKey(INPUT_RIGHT, SDL_SCANCODE_RIGHT); + mInput2->bindKey(INPUT_ACCEPT, SDL_SCANCODE_RETURN); + mInput2->bindKey(INPUT_CANCEL, SDL_SCANCODE_ESCAPE); +#ifdef __MIPSEL__ + mInput2->bindKey(INPUT_BUTTON_1, SDL_SCANCODE_LSHIFT); + mInput2->bindKey(INPUT_BUTTON_2, SDL_SCANCODE_SPACE); + mInput2->bindKey(INPUT_BUTTON_3, SDL_SCANCODE_LCTRL); +#else + mInput2->bindKey(INPUT_BUTTON_1, SDL_SCANCODE_Q); + mInput2->bindKey(INPUT_BUTTON_2, SDL_SCANCODE_W); + mInput2->bindKey(INPUT_BUTTON_3, SDL_SCANCODE_E); +#endif + mInput2->bindKey(INPUT_BUTTON_4, SDL_SCANCODE_ESCAPE); // PAUSE + mInput2->bindKey(INPUT_BUTTON_5, SDL_SCANCODE_ESCAPE); // ESCAPE } // Inicializa JailAudio @@ -439,14 +460,14 @@ void Director::runIntro() void Director::runTitle() { - mTitle = new Title(mWindow, mRenderer, mInput, mFileList, mOptions, mTextStrings); + mTitle = new Title(mWindow, mRenderer, mInput1, mFileList, mOptions, mTextStrings); setSection(mTitle->run(mSection.subsection)); delete mTitle; } void Director::runGame() { - mGame = new Game(mRenderer, mFileList, mTextStrings, mInput, false); + mGame = new Game(2, mRenderer, mFileList, mTextStrings, mInput1, mInput2, false); setSection(mGame->run()); delete mGame; } diff --git a/source/director.h b/source/director.h index ba4d4d6..69954ec 100644 --- a/source/director.h +++ b/source/director.h @@ -32,7 +32,8 @@ private: SDL_Window *mWindow; // La ventana donde dibujamos SDL_Renderer *mRenderer; // El renderizador de la ventana - Input *mInput; + Input *mInput1; // Objeto Input para gestionar las entradas + Input *mInput2; // Objeto Input para gestionar las entradas Logo *mLogo; // Objeto para la sección del logo Intro *mIntro; // Objeto para la sección de la intro diff --git a/source/game.cpp b/source/game.cpp index b8bfbc1..617b688 100644 --- a/source/game.cpp +++ b/source/game.cpp @@ -5,18 +5,20 @@ #endif // Constructor -Game::Game(SDL_Renderer *renderer, std::string *filelist, std::string *textStrings, Input *input, bool demo) +Game::Game(int numPlayers, SDL_Renderer *renderer, std::string *filelist, std::string *textStrings, Input *input1, Input *input2, bool demo) { // Copia los punteros mRenderer = renderer; mFileList = filelist; mTextStrings = textStrings; - mInput = input; + mInput[0] = input1; + mInput[1] = input2; mDemo.enabled = demo; + mNumPlayers = numPlayers; // Crea los objetos - mPlayer = new Player(); - + for (int i = 0; i < mNumPlayers; i++) + mPlayer[i] = new Player(); for (int i = 0; i < MAX_BALLOONS; i++) mBalloon[i] = new Balloon(); for (int i = 0; i < MAX_BULLETS; i++) @@ -31,18 +33,22 @@ Game::Game(SDL_Renderer *renderer, std::string *filelist, std::string *textStrin mTextureGameBG = new LTexture(); mTextureGameText = new LTexture(); mTextureItems = new LTexture(); - mTexturePlayerHead = new LTexture(); - mTexturePlayerBody = new LTexture(); - mTexturePlayerDeath = new LTexture(); - mTexturePlayerLegs = new LTexture(); + mTexturePlayer1Head = new LTexture(); + mTexturePlayer1Body = new LTexture(); + mTexturePlayer1Death = new LTexture(); + mTexturePlayer1Legs = new LTexture(); + mTexturePlayer2Head = new LTexture(); + mTexturePlayer2Body = new LTexture(); + mTexturePlayer2Death = new LTexture(); + mTexturePlayer2Legs = new LTexture(); mTextureText = new LTexture(); mTextureText2 = new LTexture(); mText = new Text(mTextureText, mRenderer); mTextX2 = new Text(mTextureText2, mRenderer); - mMenuGameOver = new Menu(mRenderer, mText, mInput, mFileList); - mMenuPause = new Menu(mRenderer, mText, mInput, mFileList); + mMenuGameOver = new Menu(mRenderer, mText, mInput[0], mFileList); + mMenuPause = new Menu(mRenderer, mText, mInput[0], mFileList); mFade = new Fade(mRenderer); mEventHandler = new SDL_Event(); @@ -78,11 +84,14 @@ Game::~Game() { mRenderer = nullptr; mFileList = nullptr; - mInput = nullptr; - - delete mPlayer; - mPlayer = nullptr; + mInput[0] = nullptr; + mInput[1] = nullptr; + for (int i = 0; i < mNumPlayers; i++) + { + delete mPlayer[i]; + mPlayer[i] = nullptr; + } for (int i = 0; i < MAX_BALLOONS; i++) { delete mBalloon[i]; @@ -124,21 +133,37 @@ Game::~Game() delete mTextureItems; mTextureItems = nullptr; - mTexturePlayerHead->unload(); - delete mTexturePlayerHead; - mTexturePlayerHead = nullptr; + mTexturePlayer1Head->unload(); + delete mTexturePlayer1Head; + mTexturePlayer1Head = nullptr; - mTexturePlayerBody->unload(); - delete mTexturePlayerBody; - mTexturePlayerBody = nullptr; + mTexturePlayer1Body->unload(); + delete mTexturePlayer1Body; + mTexturePlayer1Body = nullptr; - mTexturePlayerDeath->unload(); - delete mTexturePlayerDeath; - mTexturePlayerDeath = nullptr; + mTexturePlayer1Death->unload(); + delete mTexturePlayer1Death; + mTexturePlayer1Death = nullptr; - mTexturePlayerLegs->unload(); - delete mTexturePlayerLegs; - mTexturePlayerLegs = nullptr; + mTexturePlayer1Legs->unload(); + delete mTexturePlayer1Legs; + mTexturePlayer1Legs = nullptr; + + mTexturePlayer2Head->unload(); + delete mTexturePlayer2Head; + mTexturePlayer2Head = nullptr; + + mTexturePlayer2Body->unload(); + delete mTexturePlayer2Body; + mTexturePlayer2Body = nullptr; + + mTexturePlayer2Death->unload(); + delete mTexturePlayer2Death; + mTexturePlayer2Death = nullptr; + + mTexturePlayer2Legs->unload(); + delete mTexturePlayer2Legs; + mTexturePlayer2Legs = nullptr; mTextureText->unload(); delete mTextureText; @@ -368,8 +393,14 @@ void Game::init() mSpritePowerMeter->init(PLAY_AREA_CENTER_THIRD_QUARTER_X - 20, HISCORE_NUMBER_Y + 4, 40, 8, mTextureGameBG, mRenderer); mSpritePowerMeter->setSpriteClip(256, 192 - 8, 40, 8); - // Objeto jugador - mPlayer->init(PLAY_AREA_CENTER_X - 11, PLAY_AREA_BOTTOM - 24, mTexturePlayerLegs, mTexturePlayerBody, mTexturePlayerHead, mRenderer); + // Vector de jugadores + if (mNumPlayers == 1) + mPlayer[0]->init(PLAY_AREA_CENTER_X - 11, PLAY_AREA_BOTTOM - 24, mTexturePlayer1Legs, mTexturePlayer1Body, mTexturePlayer1Head, mRenderer); + if (mNumPlayers == 2) + { + mPlayer[0]->init((PLAY_AREA_CENTER_FIRST_QUARTER_X * ((0 * 2) + 1)) - 11, PLAY_AREA_BOTTOM - 24, mTexturePlayer1Legs, mTexturePlayer1Body, mTexturePlayer1Head, mRenderer); + mPlayer[1]->init((PLAY_AREA_CENTER_FIRST_QUARTER_X * ((1 * 2) + 1)) - 11, PLAY_AREA_BOTTOM - 24, mTexturePlayer2Legs, mTexturePlayer2Body, mTexturePlayer2Head, mRenderer); + } // Establece a cero todos los valores del vector de objetos globo resetBalloons(); @@ -455,10 +486,17 @@ bool Game::loadMedia() // Texturas success &= loadTextureFromFile(mTextureText, mFileList[30], mRenderer); success &= loadTextureFromFile(mTextureText2, mFileList[29], mRenderer); - success &= loadTextureFromFile(mTexturePlayerLegs, mFileList[39], mRenderer); - success &= loadTextureFromFile(mTexturePlayerHead, mFileList[41], mRenderer); - success &= loadTextureFromFile(mTexturePlayerBody, mFileList[37], mRenderer); - success &= loadTextureFromFile(mTexturePlayerDeath, mFileList[38], mRenderer); + + success &= loadTextureFromFile(mTexturePlayer1Legs, mFileList[39], mRenderer); + success &= loadTextureFromFile(mTexturePlayer1Head, mFileList[41], mRenderer); + success &= loadTextureFromFile(mTexturePlayer1Body, mFileList[37], mRenderer); + success &= loadTextureFromFile(mTexturePlayer1Death, mFileList[38], mRenderer); + + success &= loadTextureFromFile(mTexturePlayer2Legs, mFileList[44], mRenderer); + success &= loadTextureFromFile(mTexturePlayer2Head, mFileList[45], mRenderer); + success &= loadTextureFromFile(mTexturePlayer2Body, mFileList[42], mRenderer); + success &= loadTextureFromFile(mTexturePlayer2Death, mFileList[43], mRenderer); + success &= loadTextureFromFile(mTextureBalloon, mFileList[24], mRenderer); success &= loadTextureFromFile(mTextureBullet, mFileList[25], mRenderer); success &= loadTextureFromFile(mTextureGameBG, mFileList[31], mRenderer); @@ -1511,7 +1549,7 @@ void Game::renderScoreBoard() color_t color = {0, 0, 0}; // Si el jugador esta muerto, no pintes el fondo del marcador, así que pase por encima cuando sale despedido - if (mPlayer->isAlive()) + if (mPlayer[0]->isAlive()) mSpriteScoreBoard->render(); //if (!mDemo.enabled) @@ -1529,9 +1567,9 @@ void Game::renderScoreBoard() mText->writeColored(MULTIPLIER_WORD_X, MULTIPLIER_WORD_Y - 6, mTextStrings[41], color); color.g = 192; - mTextX2->writeShadowed(PLAY_AREA_CENTER_X - 16, SCORE_WORD_Y + 5, std::to_string(mPlayer->getScoreMultiplier()).substr(0, 1), color, 1); + mTextX2->writeShadowed(PLAY_AREA_CENTER_X - 16, SCORE_WORD_Y + 5, std::to_string(mPlayer[0]->getScoreMultiplier()).substr(0, 1), color, 1); mText->writeShadowed(PLAY_AREA_CENTER_X - 2, SCORE_WORD_Y + 12, ".", color); - mText->writeShadowed(PLAY_AREA_CENTER_X + 4, SCORE_WORD_Y + 12, std::to_string(mPlayer->getScoreMultiplier()).substr(2, 1), color); + mText->writeShadowed(PLAY_AREA_CENTER_X + 4, SCORE_WORD_Y + 12, std::to_string(mPlayer[0]->getScoreMultiplier()).substr(2, 1), color); // STAGE mText->writeCentered(PLAY_AREA_CENTER_FIRST_QUARTER_X, SCORE_NUMBER_Y + 4, mTextStrings[42] + std::to_string(mStage[mCurrentStage].number), 0); @@ -1548,17 +1586,20 @@ void Game::renderScoreBoard() // Actualiza las variables del jugador void Game::updatePlayer() { - mPlayer->update(); - - // Comprueba la colisión entre el jugador y los globos - if (checkPlayerBalloonCollision()) + for (int i = 0; i < mNumPlayers; i++) { - if (mPlayer->isAlive()) + mPlayer[i]->update(); + + // Comprueba la colisión entre el jugador y los globos + if (checkPlayerBalloonCollision()) { - if (mDemo.enabled) - mSection = {PROG_SECTION_TITLE, TITLE_SECTION_INSTRUCTIONS}; - else - killPlayer(); + if (mPlayer[i]->isAlive()) + { + if (mDemo.enabled) + mSection = {PROG_SECTION_TITLE, TITLE_SECTION_INSTRUCTIONS}; + else + killPlayer(); + } } } } @@ -1601,7 +1642,7 @@ void Game::updateStage() // Actualiza el estado de muerte void Game::updateDeath() { - if (!mPlayer->isAlive()) + if (!mPlayer[0]->isAlive()) { if (mDeathCounter > 0) { @@ -1823,8 +1864,8 @@ void Game::updateBalloonSpeed() void Game::popBalloon(Uint8 index) { // Otorga los puntos correspondientes al globo - mPlayer->addScore(Uint32(mBalloon[index]->getScore() * mPlayer->getScoreMultiplier())); - setScore(mPlayer->getScore()); + mPlayer[0]->addScore(Uint32(mBalloon[index]->getScore() * mPlayer[0]->getScoreMultiplier())); + setScore(mPlayer[0]->getScore()); updateHiScore(); // Aumenta el poder de la fase @@ -1914,8 +1955,8 @@ void Game::destroyBalloon(Uint8 index) } // Otorga los puntos correspondientes al globo - mPlayer->addScore(Uint32(score * mPlayer->getScoreMultiplier())); - setScore(mPlayer->getScore()); + mPlayer[0]->addScore(Uint32(score * mPlayer[0]->getScoreMultiplier())); + setScore(mPlayer[0]->getScore()); updateHiScore(); // Aumenta el poder de la fase @@ -1991,10 +2032,11 @@ Uint8 Game::countBalloons() // Comprueba la colisión entre el jugador y los globos activos bool Game::checkPlayerBalloonCollision() { - for (int i = 0; i < MAX_BALLOONS; i++) - if ((mBalloon[i]->isEnabled()) && !(mBalloon[i]->isStopped()) && !(mBalloon[i]->isInvulnerable())) - if (checkCollision(mPlayer->getCollider(), mBalloon[i]->getCollider())) - return true; + for (int j = 0; j < mNumPlayers; j++) + for (int i = 0; i < MAX_BALLOONS; i++) + if ((mBalloon[i]->isEnabled()) && !(mBalloon[i]->isStopped()) && !(mBalloon[i]->isInvulnerable())) + if (checkCollision(mPlayer[j]->getCollider(), mBalloon[i]->getCollider())) + return true; return false; } @@ -2002,57 +2044,59 @@ bool Game::checkPlayerBalloonCollision() // Comprueba la colisión entre el jugador y los items void Game::checkPlayerItemCollision() { - if (mPlayer->isAlive()) - for (int i = 0; i < MAX_ITEMS; i++) - { - if (mItem[i]->isEnabled()) - { - if (checkCollision(mPlayer->getCollider(), mItem[i]->getCollider())) - { - switch (mItem[i]->getClass()) - { - case ITEM_POINTS_1_DISK: - mPlayer->addScore(1000); - setScore(mPlayer->getScore()); - updateHiScore(); - createItemScoreSprite(mItem[i]->getPosX() + (mItem[i]->getWidth() / 2) - (m1000Bitmap->getWidth() / 2), mPlayer->getPosY(), m1000Bitmap); - JA_PlaySound(mSoundItemPickup); - break; - case ITEM_POINTS_2_GAVINA: - mPlayer->addScore(2500); - setScore(mPlayer->getScore()); - updateHiScore(); - createItemScoreSprite(mItem[i]->getPosX() + (mItem[i]->getWidth() / 2) - (m2500Bitmap->getWidth() / 2), mPlayer->getPosY(), m2500Bitmap); - JA_PlaySound(mSoundItemPickup); - break; - case ITEM_POINTS_3_PACMAR: - mPlayer->addScore(5000); - setScore(mPlayer->getScore()); - updateHiScore(); - createItemScoreSprite(mItem[i]->getPosX() + (mItem[i]->getWidth() / 2) - (m5000Bitmap->getWidth() / 2), mPlayer->getPosY(), m5000Bitmap); - JA_PlaySound(mSoundItemPickup); - break; - case ITEM_CLOCK: - enableTimeStopItem(); - JA_PlaySound(mSoundItemPickup); - break; - case ITEM_COFFEE: - mPlayer->giveExtraHit(); - JA_PlaySound(mSoundItemPickup); - break; - case ITEM_COFFEE_MACHINE: - mPlayer->setPowerUp(true); - JA_PlaySound(mSoundItemPickup); - mCoffeeMachineEnabled = false; - break; + for (int j = 0; j < mNumPlayers; j++) - default: - break; + if (mPlayer[j]->isAlive()) + for (int i = 0; i < MAX_ITEMS; i++) + { + if (mItem[i]->isEnabled()) + { + if (checkCollision(mPlayer[j]->getCollider(), mItem[i]->getCollider())) + { + switch (mItem[i]->getClass()) + { + case ITEM_POINTS_1_DISK: + mPlayer[j]->addScore(1000); + setScore(mPlayer[j]->getScore()); + updateHiScore(); + createItemScoreSprite(mItem[i]->getPosX() + (mItem[i]->getWidth() / 2) - (m1000Bitmap->getWidth() / 2), mPlayer[j]->getPosY(), m1000Bitmap); + JA_PlaySound(mSoundItemPickup); + break; + case ITEM_POINTS_2_GAVINA: + mPlayer[j]->addScore(2500); + setScore(mPlayer[j]->getScore()); + updateHiScore(); + createItemScoreSprite(mItem[i]->getPosX() + (mItem[i]->getWidth() / 2) - (m2500Bitmap->getWidth() / 2), mPlayer[j]->getPosY(), m2500Bitmap); + JA_PlaySound(mSoundItemPickup); + break; + case ITEM_POINTS_3_PACMAR: + mPlayer[j]->addScore(5000); + setScore(mPlayer[j]->getScore()); + updateHiScore(); + createItemScoreSprite(mItem[i]->getPosX() + (mItem[i]->getWidth() / 2) - (m5000Bitmap->getWidth() / 2), mPlayer[j]->getPosY(), m5000Bitmap); + JA_PlaySound(mSoundItemPickup); + break; + case ITEM_CLOCK: + enableTimeStopItem(); + JA_PlaySound(mSoundItemPickup); + break; + case ITEM_COFFEE: + mPlayer[j]->giveExtraHit(); + JA_PlaySound(mSoundItemPickup); + break; + case ITEM_COFFEE_MACHINE: + mPlayer[j]->setPowerUp(true); + JA_PlaySound(mSoundItemPickup); + mCoffeeMachineEnabled = false; + break; + + default: + break; + } + mItem[i]->erase(); } - mItem[i]->erase(); } } - } } // Comprueba y procesa la colisión entre las balas y los globos @@ -2063,7 +2107,7 @@ void Game::checkBulletBalloonCollision() if (mBalloon[i]->isEnabled() && (!mBalloon[i]->isInvulnerable()) && mBullet[j]->isActive()) if (checkCollision(mBalloon[i]->getCollider(), mBullet[j]->getCollider())) { - mPlayer->incScoreMultiplier(); + mPlayer[0]->incScoreMultiplier(); popBalloon(i); if (!mDemo.enabled) JA_PlaySound(mSoundBalloon); @@ -2088,7 +2132,7 @@ void Game::moveBullets() for (int i = 0; i < MAX_BULLETS; i++) if (mBullet[i]->isActive()) if (mBullet[i]->move() == MSG_BULLET_OUT) - mPlayer->decScoreMultiplier(); + mPlayer[0]->decScoreMultiplier(); } // Pinta las balas activas @@ -2296,7 +2340,7 @@ void Game::throwPlayer(int x, int y) const int sentit = ((rand() % 2) ? 1 : -1); mDeathIndex = getSmartSpriteFreeIndex(); - mSmartSprite[mDeathIndex]->init(mTexturePlayerDeath, mRenderer); + mSmartSprite[mDeathIndex]->init(mTexturePlayer1Death, mRenderer); mSmartSprite[mDeathIndex]->setPosX(x); mSmartSprite[mDeathIndex]->setPosY(y); mSmartSprite[mDeathIndex]->setWidth(24); @@ -2346,26 +2390,28 @@ void Game::resetSmartSprites() // Acciones a realizar cuando el jugador muere void Game::killPlayer() { - if (!mPlayer->isInvulnerable()) - { - if (mPlayer->hasExtraHit()) + for (int i = 0; i < mNumPlayers; i++) + + if (!mPlayer[i]->isInvulnerable()) { - mPlayer->removeExtraHit(); - throwCoffee(mPlayer->getPosX() + (mPlayer->getWidth() / 2), mPlayer->getPosY() + (mPlayer->getHeight() / 2)); - JA_PlaySound(mSoundCoffeeOut); + if (mPlayer[i]->hasExtraHit()) + { + mPlayer[i]->removeExtraHit(); + throwCoffee(mPlayer[i]->getPosX() + (mPlayer[i]->getWidth() / 2), mPlayer[i]->getPosY() + (mPlayer[i]->getHeight() / 2)); + JA_PlaySound(mSoundCoffeeOut); + } + else + { + stopAllBalloons(10); + JA_StopMusic(); + JA_PlaySound(mSoundPlayerCollision); + shakeScreen(); + SDL_Delay(500); + JA_PlaySound(mSoundCoffeeOut); + throwPlayer(mPlayer[i]->getPosX(), mPlayer[i]->getPosY()); + mPlayer[i]->setAlive(false); + } } - else - { - stopAllBalloons(10); - JA_StopMusic(); - JA_PlaySound(mSoundPlayerCollision); - shakeScreen(); - SDL_Delay(500); - JA_PlaySound(mSoundCoffeeOut); - throwPlayer(mPlayer->getPosX(), mPlayer->getPosY()); - mPlayer->setAlive(false); - } - } } // Calcula y establece el valor de amenaza en funcion de los globos activos @@ -2594,8 +2640,9 @@ void Game::renderPlayField() renderItems(); renderSmartSprites(); renderScoreBoard(); - mPlayer->render(); - if ((mDeathCounter <= 150) && !mPlayer->isAlive()) + for (int i = 0; i < mNumPlayers; i++) + mPlayer[i]->render(); + if ((mDeathCounter <= 150) && !mPlayer[0]->isAlive()) renderDeathFade(150 - mDeathCounter); if ((mGameCompleted) && (mGameCompletedCounter >= 300)) renderDeathFade(mGameCompletedCounter - 300); @@ -2636,40 +2683,40 @@ void Game::checkGameInput() if (mDemo.enabled) { if (mDemo.dataFile[mDemo.counter].left == 1) - mPlayer->setInput(INPUT_LEFT); + mPlayer[0]->setInput(INPUT_LEFT); if (mDemo.dataFile[mDemo.counter].right == 1) - mPlayer->setInput(INPUT_RIGHT); + mPlayer[0]->setInput(INPUT_RIGHT); if (mDemo.dataFile[mDemo.counter].noInput == 1) - mPlayer->setInput(NO_INPUT); + mPlayer[0]->setInput(NO_INPUT); if (mDemo.dataFile[mDemo.counter].fire == 1) - if (mPlayer->canFire()) + if (mPlayer[0]->canFire()) { - mPlayer->setInput(INPUT_FIRE_UP); - createBullet(mPlayer->getPosX() + (mPlayer->getWidth() / 2) - 4, mPlayer->getPosY() + (mPlayer->getHeight() / 2), BULLET_UP, mPlayer->isPowerUp()); - mPlayer->setFireCooldown(10); + mPlayer[0]->setInput(INPUT_FIRE_UP); + createBullet(mPlayer[0]->getPosX() + (mPlayer[0]->getWidth() / 2) - 4, mPlayer[0]->getPosY() + (mPlayer[0]->getHeight() / 2), BULLET_UP, mPlayer[0]->isPowerUp()); + mPlayer[0]->setFireCooldown(10); } if (mDemo.dataFile[mDemo.counter].fireLeft == 1) - if (mPlayer->canFire()) + if (mPlayer[0]->canFire()) { - mPlayer->setInput(INPUT_FIRE_LEFT); - createBullet(mPlayer->getPosX() + (mPlayer->getWidth() / 2) - 4, mPlayer->getPosY() + (mPlayer->getHeight() / 2), BULLET_UP, mPlayer->isPowerUp()); - mPlayer->setFireCooldown(10); + mPlayer[0]->setInput(INPUT_FIRE_LEFT); + createBullet(mPlayer[0]->getPosX() + (mPlayer[0]->getWidth() / 2) - 4, mPlayer[0]->getPosY() + (mPlayer[0]->getHeight() / 2), BULLET_UP, mPlayer[0]->isPowerUp()); + mPlayer[0]->setFireCooldown(10); } if (mDemo.dataFile[mDemo.counter].fireRight == 1) - if (mPlayer->canFire()) + if (mPlayer[0]->canFire()) { - mPlayer->setInput(INPUT_FIRE_RIGHT); - createBullet(mPlayer->getPosX() + (mPlayer->getWidth() / 2) - 4, mPlayer->getPosY() + (mPlayer->getHeight() / 2), BULLET_UP, mPlayer->isPowerUp()); - mPlayer->setFireCooldown(10); + mPlayer[0]->setInput(INPUT_FIRE_RIGHT); + createBullet(mPlayer[0]->getPosX() + (mPlayer[0]->getWidth() / 2) - 4, mPlayer[0]->getPosY() + (mPlayer[0]->getHeight() / 2), BULLET_UP, mPlayer[0]->isPowerUp()); + mPlayer[0]->setFireCooldown(10); } // Comprueba el input de pausa - if (mInput->checkInput(INPUT_PAUSE, REPEAT_FALSE)) + if (mInput[0]->checkInput(INPUT_PAUSE, REPEAT_FALSE)) mSection.name = PROG_SECTION_TITLE; // Incrementa el contador de la demo @@ -2679,97 +2726,99 @@ void Game::checkGameInput() mSection = {PROG_SECTION_TITLE, TITLE_SECTION_INSTRUCTIONS}; } // Modo Demo no activo - else if (mPlayer->isAlive()) - { - // Input a la izquierda - if (mInput->checkInput(INPUT_LEFT, REPEAT_TRUE)) - { - mPlayer->setInput(INPUT_LEFT); - mDemo.keys.left = 1; - } - else - { - // Input a la derecha - if (mInput->checkInput(INPUT_RIGHT, REPEAT_TRUE)) + else + for (int i = 0; i < mNumPlayers; i++) + if (mPlayer[i]->isAlive()) { - mPlayer->setInput(INPUT_RIGHT); - mDemo.keys.right = 1; + // Input a la izquierda + if (mInput[i]->checkInput(INPUT_LEFT, REPEAT_TRUE)) + { + mPlayer[i]->setInput(INPUT_LEFT); + mDemo.keys.left = 1; + } + else + { + // Input a la derecha + if (mInput[i]->checkInput(INPUT_RIGHT, REPEAT_TRUE)) + { + mPlayer[i]->setInput(INPUT_RIGHT); + mDemo.keys.right = 1; + } + else + { + // Ninguno de los dos inputs anteriores + mPlayer[i]->setInput(NO_INPUT); + mDemo.keys.noInput = 1; + } + } + // Comprueba el input de disparar al centro + if (mInput[i]->checkInput(INPUT_BUTTON_2, REPEAT_TRUE)) + { + if (mPlayer[i]->canFire()) + { + mPlayer[i]->setInput(INPUT_FIRE_UP); + createBullet(mPlayer[i]->getPosX() + (mPlayer[i]->getWidth() / 2) - 4, mPlayer[i]->getPosY() + (mPlayer[i]->getHeight() / 2), BULLET_UP, mPlayer[i]->isPowerUp()); + mPlayer[i]->setFireCooldown(10); + + // Reproduce el sonido de disparo + JA_PlaySound(mSoundBullet); + + mDemo.keys.fire = 1; + } + } + + // Comprueba el input de disparar a la izquierda + if (mInput[i]->checkInput(INPUT_BUTTON_1, REPEAT_TRUE)) + { + if (mPlayer[i]->canFire()) + { + mPlayer[i]->setInput(INPUT_FIRE_LEFT); + createBullet(mPlayer[i]->getPosX() + (mPlayer[i]->getWidth() / 2) - 4, mPlayer[i]->getPosY() + (mPlayer[i]->getHeight() / 2), BULLET_LEFT, mPlayer[i]->isPowerUp()); + mPlayer[i]->setFireCooldown(10); + + // Reproduce el sonido de disparo + JA_PlaySound(mSoundBullet); + + mDemo.keys.fireLeft = 1; + } + } + + // Comprueba el input de disparar a la derecha + if (mInput[i]->checkInput(INPUT_BUTTON_3, REPEAT_TRUE)) + { + if (mPlayer[i]->canFire()) + { + mPlayer[i]->setInput(INPUT_FIRE_RIGHT); + createBullet(mPlayer[i]->getPosX() + (mPlayer[i]->getWidth() / 2) - 4, mPlayer[i]->getPosY() + (mPlayer[i]->getHeight() / 2), BULLET_RIGHT, mPlayer[i]->isPowerUp()); + mPlayer[i]->setFireCooldown(10); + + // Reproduce el sonido de disparo + JA_PlaySound(mSoundBullet); + + mDemo.keys.fireRight = 1; + } + } + + // Comprueba el input de pausa + if (mInput[i]->checkInput(INPUT_CANCEL, REPEAT_FALSE)) + { + mSection.subsection = GAME_SECTION_PAUSE; + + if (JA_GetMusicState() == JA_MUSIC_PLAYING) + JA_PauseMusic(); + } + + if (mDemo.counter < TOTAL_DEMO_DATA) + { + if (mDemo.recording) + mDemo.dataFile[mDemo.counter] = mDemo.keys; + mDemo.counter++; + } + else if (mDemo.recording) + { + mSection.name = PROG_SECTION_QUIT; + } } - else - { - // Ninguno de los dos inputs anteriores - mPlayer->setInput(NO_INPUT); - mDemo.keys.noInput = 1; - } - } - // Comprueba el input de disparar al centro - if (mInput->checkInput(INPUT_BUTTON_2, REPEAT_TRUE)) - { - if (mPlayer->canFire()) - { - mPlayer->setInput(INPUT_FIRE_UP); - createBullet(mPlayer->getPosX() + (mPlayer->getWidth() / 2) - 4, mPlayer->getPosY() + (mPlayer->getHeight() / 2), BULLET_UP, mPlayer->isPowerUp()); - mPlayer->setFireCooldown(10); - - // Reproduce el sonido de disparo - JA_PlaySound(mSoundBullet); - - mDemo.keys.fire = 1; - } - } - - // Comprueba el input de disparar a la izquierda - if (mInput->checkInput(INPUT_BUTTON_1, REPEAT_TRUE)) - { - if (mPlayer->canFire()) - { - mPlayer->setInput(INPUT_FIRE_LEFT); - createBullet(mPlayer->getPosX() + (mPlayer->getWidth() / 2) - 4, mPlayer->getPosY() + (mPlayer->getHeight() / 2), BULLET_LEFT, mPlayer->isPowerUp()); - mPlayer->setFireCooldown(10); - - // Reproduce el sonido de disparo - JA_PlaySound(mSoundBullet); - - mDemo.keys.fireLeft = 1; - } - } - - // Comprueba el input de disparar a la derecha - if (mInput->checkInput(INPUT_BUTTON_3, REPEAT_TRUE)) - { - if (mPlayer->canFire()) - { - mPlayer->setInput(INPUT_FIRE_RIGHT); - createBullet(mPlayer->getPosX() + (mPlayer->getWidth() / 2) - 4, mPlayer->getPosY() + (mPlayer->getHeight() / 2), BULLET_RIGHT, mPlayer->isPowerUp()); - mPlayer->setFireCooldown(10); - - // Reproduce el sonido de disparo - JA_PlaySound(mSoundBullet); - - mDemo.keys.fireRight = 1; - } - } - - // Comprueba el input de pausa - if (mInput->checkInput(INPUT_CANCEL, REPEAT_FALSE)) - { - mSection.subsection = GAME_SECTION_PAUSE; - - if (JA_GetMusicState() == JA_MUSIC_PLAYING) - JA_PauseMusic(); - } - - if (mDemo.counter < TOTAL_DEMO_DATA) - { - if (mDemo.recording) - mDemo.dataFile[mDemo.counter] = mDemo.keys; - mDemo.counter++; - } - else if (mDemo.recording) - { - mSection.name = PROG_SECTION_QUIT; - } - } } // Pinta diferentes mensajes en la pantalla @@ -2864,7 +2913,8 @@ void Game::shakeScreen() renderBalloons(); renderBullets(); renderItems(); - mPlayer->render(); + for (int i = 0; i < mNumPlayers; i++) + mPlayer[i]->render(); renderScoreBoard(); // Actualiza la pantalla @@ -2896,7 +2946,7 @@ section_t Game::run() { // Reproduce la música if (!mGameCompleted) - if (mPlayer->isAlive()) + if (mPlayer[0]->isAlive()) JA_PlayMusic(mMusicPlaying); } @@ -2959,8 +3009,8 @@ section_t Game::run() break; case SDL_SCANCODE_I: - mPlayer->setInvulnerable(true); - mPlayer->setInvulnerableCounter(65000); + mPlayer[0]->setInvulnerable(true); + mPlayer[0]->setInvulnerableCounter(65000); break; case SDL_SCANCODE_M: @@ -3039,7 +3089,8 @@ void Game::runPausedGame() renderBackground(); renderBalloons(); renderBullets(); - mPlayer->render(); + for (int i = 0; i < mNumPlayers; i++) + mPlayer[i]->render(); renderScoreBoard(); mMenuPause->render(); mFade->render(); @@ -3130,7 +3181,7 @@ void Game::runGameOverScreen() // Dibuja los objetos mTextX2->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 4), mTextStrings[43], 0); - mText->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 1), mTextStrings[44] + std::to_string(mPlayer->getScore()), 0); + mText->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 1), mTextStrings[44] + std::to_string(mPlayer[0]->getScore()), 0); mText->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y + BLOCK * 2, mTextStrings[45], 0); mMenuGameOver->render(); mFade->render(); @@ -3175,7 +3226,7 @@ void Game::renderDebugInfo() mText->writeShadowed(2, 2 + 3 * BLOCK, "mCounter: " + std::to_string(mCounter), color); mText->writeShadowed(2, 2 + 4 * BLOCK, "(R)enemyset: " + std::to_string(mDebug.enemySet), color); mText->writeShadowed(2, 2 + 5 * BLOCK, "RGB: " + std::to_string(mDebug.gradR) + "," + std::to_string(mDebug.gradG) + "," + std::to_string(mDebug.gradB), color); - mText->writeShadowed(2, 2 + 6 * BLOCK, "(I)invuln: " + std::to_string(mPlayer->getInvulnerableCounter()), color); + mText->writeShadowed(2, 2 + 6 * BLOCK, "(I)invuln: " + std::to_string(mPlayer[0]->getInvulnerableCounter()), color); mText->writeShadowed(2, 2 + 7 * BLOCK, "balloons: " + std::to_string(countBalloons()), color); mText->writeShadowed(2, 2 + 8 * BLOCK, "balloonsPop: " + std::to_string(mBalloonsPopped), color); mText->writeShadowed(2, 2 + 9 * BLOCK, "(Z-X)ballSped:" + std::to_string(mEnemySpeed), color); @@ -3268,12 +3319,12 @@ void Game::updateHelper() // Solo ofrece ayuda cuando la amenaza o la velocidad es elevada if (mMenaceCurrent > 15) { - if (mPlayer->getCoffees() == 0) + if (mPlayer[0]->getCoffees() == 0) mHelper.needCoffee = true; else mHelper.needCoffee = false; - if (!mPlayer->isPowerUp()) + if (!mPlayer[0]->isPowerUp()) mHelper.needCoffeeMachine = true; else mHelper.needCoffeeMachine = false; diff --git a/source/game.h b/source/game.h index a2797e5..a2bc814 100644 --- a/source/game.h +++ b/source/game.h @@ -82,26 +82,31 @@ private: SDL_Renderer *mRenderer; // El renderizador de la ventana std::string *mFileList; // Lista de ficheros con los recursos std::string *mTextStrings; // Vector con los textos del juego - Input *mInput; // Manejador de entrada + Input *mInput[2]; // Manejador de entrada - Player *mPlayer; // El jugador + int mNumPlayers; // Numero de jugadores + Player *mPlayer[2]; // Vector con los jugadores jugador Balloon *mBalloon[MAX_BALLOONS]; // Vector con los objetos globo Bullet *mBullet[MAX_BULLETS]; // Vector con los objetos bala Item *mItem[MAX_ITEMS]; // Vector con los objetos item SmartSprite *mSmartSprite[MAX_SMART_SPRITES]; // Vector para almacenar y gestionar SmartSprites - LTexture *mTextureBalloon; // Textura para los enemigos - LTexture *mTextureBullet; // Textura para las balas - LTexture *mTextureGameBG; // Textura para el fondo del juego - LTexture *mTextureGameText; // Textura para los sprites con textos - LTexture *mTextureItems; // Textura para los items - LTexture *mTexturePlayerHead; // Textura para la cabeza del jugador - LTexture *mTexturePlayerBody; // Textura para el cuerpo del jugador - LTexture *mTexturePlayerDeath; // Textura para la animación de muerte del jugador - LTexture *mTexturePlayerLegs; // Textura para las piernas del jugador - LTexture *mTextureText; // Textura para el texto - LTexture *mTextureText2; // Textura para el texto + LTexture *mTextureBalloon; // Textura para los enemigos + LTexture *mTextureBullet; // Textura para las balas + LTexture *mTextureGameBG; // Textura para el fondo del juego + LTexture *mTextureGameText; // Textura para los sprites con textos + LTexture *mTextureItems; // Textura para los items + LTexture *mTexturePlayer1Head; // Textura para la cabeza del jugador1 + LTexture *mTexturePlayer1Body; // Textura para el cuerpo del jugador1 + LTexture *mTexturePlayer1Death; // Textura para la animación de muerte del jugador1 + LTexture *mTexturePlayer1Legs; // Textura para las piernas del jugador + LTexture *mTexturePlayer2Head; // Textura para la cabeza del jugador2 + LTexture *mTexturePlayer2Body; // Textura para el cuerpo del jugador2 + LTexture *mTexturePlayer2Death; // Textura para la animación de muerte del jugador2 + LTexture *mTexturePlayer2Legs; // Textura para las piernas del jugador + LTexture *mTextureText; // Textura para el texto + LTexture *mTextureText2; // Textura para el texto Text *mText; // Variable con todos los objetos de texto Text *mTextX2; // Variable con todos los objetos de texto @@ -202,7 +207,7 @@ private: public: // Constructor - Game(SDL_Renderer *renderer, std::string *filelist, std::string *textStrings, Input *input, bool demo); + Game(int numPlayers, SDL_Renderer *renderer, std::string *filelist, std::string *textStrings, Input *input1, Input *input2, bool demo); // Destructor ~Game(); diff --git a/source/title.cpp b/source/title.cpp index 8f24f8e..3cfedee 100644 --- a/source/title.cpp +++ b/source/title.cpp @@ -684,7 +684,7 @@ void Title::runInstructions(Uint8 mode) // Ejecuta el juego en modo demo void Title::runDemoGame() { - mDemoGame = new Game(mRenderer, mFileList, mTextStrings, mInput, true); + mDemoGame = new Game(1, mRenderer, mFileList, mTextStrings, mInput, mInput, true); mDemoGame->run(); delete mDemoGame; } \ No newline at end of file