diff --git a/data/gfx/game_text/game_text_stop.png b/data/gfx/game_text/game_text_stop.png new file mode 100644 index 0000000..dcca8d8 Binary files /dev/null and b/data/gfx/game_text/game_text_stop.png differ diff --git a/source/balloon.cpp b/source/balloon.cpp index 60243b5..fbfb6cb 100644 --- a/source/balloon.cpp +++ b/source/balloon.cpp @@ -15,6 +15,7 @@ Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel vx_(vel_x), being_created_(creation_timer > 0), invulnerable_(creation_timer > 0), + stopped_(creation_timer > 0), creation_counter_(creation_timer), creation_counter_ini_(creation_timer), type_(type), @@ -83,6 +84,9 @@ Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel // Alinea el circulo de colisión con el objeto collider_.r = w_ / 2; shiftColliders(); + + // Establece la animación a usar + setAnimation(); } // Centra el globo en la posición X @@ -213,7 +217,6 @@ void Balloon::pop() void Balloon::update() { move(); - updateAnimation(); updateState(); updateBounce(); shiftSprite(); @@ -229,7 +232,7 @@ void Balloon::updateState() if (isBeingCreated()) { // Actualiza el valor de las variables - setStop(true); + stop(); setInvulnerable(true); if (creation_counter_ > 0) @@ -258,34 +261,15 @@ void Balloon::updateState() { // El contador ha llegado a cero being_created_ = false; - // visible_ = true; - setStop(false); + start(); setInvulnerable(false); - if (type_ == BalloonType::POWERBALL) - sprite_->enableRotate(); - } - } - else if (isStopped()) - { - // Solo comprueba el estado detenido cuando no se está creando - if (type_ == BalloonType::POWERBALL) - sprite_->disableRotate(); - - // Reduce el contador - if (stopped_counter_ > 0) - --stopped_counter_; - else - { - // Si el contador ha llegado a cero - setStop(false); - if (type_ == BalloonType::POWERBALL) - sprite_->enableRotate(); + setAnimation(); } } } // Establece la animación correspondiente al estado -void Balloon::updateAnimation() +void Balloon::setAnimation() { std::string creating_animation; std::string normal_animation; @@ -307,7 +291,10 @@ void Balloon::updateAnimation() } // Establece el frame de animación - sprite_->setCurrentAnimation(isBeingCreated() ? creating_animation : normal_animation); + if (use_reversed_colors_) + sprite_->setCurrentAnimation(creating_animation); + else + sprite_->setCurrentAnimation(isBeingCreated() ? creating_animation : normal_animation); } // Comprueba si el globo está habilitado @@ -364,10 +351,20 @@ BalloonType Balloon::getType() const return type_; } -// Establece el valor de la variable -void Balloon::setStop(bool state) +// Detiene el globo +void Balloon::stop() { - stopped_ = state; + stopped_ = true; + if (type_ == BalloonType::POWERBALL) + sprite_->disableRotate(); +} + +// Pone el globo en movimiento +void Balloon::start() +{ + stopped_ = false; + if (type_ == BalloonType::POWERBALL) + sprite_->enableRotate(); } // Obtiene del valor de la variable @@ -376,18 +373,6 @@ bool Balloon::isStopped() const return stopped_; } -// Establece el valor de la variable -void Balloon::setBlink(bool value) -{ - blinking_ = value; -} - -// Obtiene del valor de la variable -bool Balloon::isBlinking() const -{ - return blinking_; -} - // Establece el valor de la variable void Balloon::setInvulnerable(bool value) { @@ -406,18 +391,6 @@ bool Balloon::isBeingCreated() const return being_created_; } -// Establece el valor de la variable -void Balloon::setStoppedTimer(Uint16 time) -{ - stopped_counter_ = time; -} - -// Obtiene del valor de la variable -Uint16 Balloon::getStoppedTimer() const -{ - return stopped_counter_; -} - // Obtiene del valor de la variable Uint16 Balloon::getScore() const { @@ -509,4 +482,27 @@ bool Balloon::canBePopped() const bool Balloon::canBeDestroyed() const { return isEnabled(); +} + +// Pone el color alternativo en el globo +void Balloon::useReverseColor() +{ + if (!isBeingCreated()) + { + use_reversed_colors_ = true; + setAnimation(); + } +} + +// Pone el color normal en el globo +void Balloon::useNormalColor() +{ + use_reversed_colors_ = false; + setAnimation(); +} + +// Indica si está usando el color alternativo +bool Balloon::isUsingReversedColor() +{ + return use_reversed_colors_; } \ No newline at end of file diff --git a/source/balloon.h b/source/balloon.h index a8b0cf5..3b1cebd 100644 --- a/source/balloon.h +++ b/source/balloon.h @@ -87,32 +87,31 @@ private: std::unique_ptr sprite_; // Sprite del objeto globo // Variables - float x_; // Posición en el eje X - float y_; // Posición en el eje Y - Uint8 w_; // Ancho - Uint8 h_; // Alto - float vx_; // Velocidad en el eje X. Cantidad de pixeles a desplazarse - float vy_; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse - float gravity_; // Aceleración en el eje Y. Modifica la velocidad - float default_vy_; // Velocidad inicial que tienen al rebotar contra el suelo - float max_vy_; // Máxima velocidad que puede alcanzar el objeto en el eje Y - bool being_created_; // Indica si el globo se está creando - bool blinking_ = false; // Indica si el globo está intermitente - bool enabled_ = true; // Indica si el globo esta activo - bool invulnerable_; // Indica si el globo es invulnerable - bool stopped_ = true; // Indica si el globo está parado - Circle collider_; // Circulo de colisión del objeto - Uint16 creation_counter_; // Temporizador para controlar el estado "creandose" - Uint16 creation_counter_ini_; // Valor inicial para el temporizador para controlar el estado "creandose" - Uint16 score_; // Puntos que da el globo al ser destruido - Uint16 stopped_counter_ = 0; // Contador para controlar el estado "parado" - BalloonType type_; // Clase de globo - BalloonSize size_; // Tamaño del globo - Uint8 menace_; // Cantidad de amenaza que genera el globo - Uint32 counter_ = 0; // Contador interno - float travel_y_ = 1.0f; // Distancia que ha de recorrer el globo en el eje Y antes de que se le aplique la gravedad - float speed_; // Velocidad a la que se mueven los globos - Uint8 power_; // Cantidad de poder que alberga el globo + float x_; // Posición en el eje X + float y_; // Posición en el eje Y + Uint8 w_; // Ancho + Uint8 h_; // Alto + float vx_; // Velocidad en el eje X. Cantidad de pixeles a desplazarse + float vy_; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse + float gravity_; // Aceleración en el eje Y. Modifica la velocidad + float default_vy_; // Velocidad inicial que tienen al rebotar contra el suelo + float max_vy_; // Máxima velocidad que puede alcanzar el objeto en el eje Y + bool being_created_; // Indica si el globo se está creando + bool enabled_ = true; // Indica si el globo esta activo + bool invulnerable_; // Indica si el globo es invulnerable + bool stopped_; // Indica si el globo está parado + bool use_reversed_colors_ = false; // Indica si se ha de usar el color secundario del globo como color principal + Circle collider_; // Circulo de colisión del objeto + Uint16 creation_counter_; // Temporizador para controlar el estado "creandose" + Uint16 creation_counter_ini_; // Valor inicial para el temporizador para controlar el estado "creandose" + Uint16 score_; // Puntos que da el globo al ser destruido + BalloonType type_; // Clase de globo + BalloonSize size_; // Tamaño del globo + Uint8 menace_; // Cantidad de amenaza que genera el globo + Uint32 counter_ = 0; // Contador interno + float travel_y_ = 1.0f; // Distancia que ha de recorrer el globo en el eje Y antes de que se le aplique la gravedad + float speed_; // Velocidad a la que se mueven los globos + Uint8 power_; // Cantidad de poder que alberga el globo // Alinea el circulo de colisión con la posición del objeto globo void shiftColliders(); @@ -136,7 +135,7 @@ private: void updateState(); // Establece la animación correspondiente - void updateAnimation(); + void setAnimation(); public: // Constructor @@ -190,18 +189,15 @@ public: // Obtiene el tipo de globo BalloonType getType() const; - // Establece el valor de la variable - void setStop(bool value); + // Detiene el globo + void stop(); + + // Pone el globo en movimiento + void start(); // Obtiene del valor de la variable bool isStopped() const; - // Establece el valor de la variable - void setBlink(bool value); - - // Obtiene del valor de la variable - bool isBlinking() const; - // Establece el valor de la variable void setInvulnerable(bool value); @@ -211,12 +207,6 @@ public: // Obtiene del valor de la variable bool isBeingCreated() const; - // Establece el valor de la variable - void setStoppedTimer(Uint16 time); - - // Obtiene del valor de la variable - Uint16 getStoppedTimer() const; - // Obtiene del valor de la variable Uint16 getScore() const; @@ -234,4 +224,13 @@ public: // Indica si el globo se puede destruir bool canBeDestroyed() const; + + // Pone el color alternativo en el globo + void useReverseColor(); + + // Pone el color normal en el globo + void useNormalColor(); + + // Indica si está usando el color alternativo + bool isUsingReversedColor(); }; \ No newline at end of file diff --git a/source/director.cpp b/source/director.cpp index 860d787..59e5b3b 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -431,6 +431,7 @@ void Director::setFileList() Asset::get()->add(prefix + "/data/gfx/game_text/game_text_5000_points.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/game_text/game_text_powerup.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/game_text/game_text_one_hit.png", AssetType::BITMAP); + Asset::get()->add(prefix + "/data/gfx/game_text/game_text_stop.png", AssetType::BITMAP); } { // Intro diff --git a/source/enter_name.cpp b/source/enter_name.cpp index 81f36ed..54a06b4 100644 --- a/source/enter_name.cpp +++ b/source/enter_name.cpp @@ -16,7 +16,7 @@ void EnterName::init() // Inicia la lista de caracteres permitidos character_list_ = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-+-*/=?¿<>!\"#$%&/()"; position_ = 0; - num_characters_ = (int)character_list_.size(); + num_characters_ = static_cast(character_list_.size()); // Pone la lista de indices para que refleje el nombre updateCharacterIndex(); @@ -36,7 +36,7 @@ void EnterName::incPosition() // Decrementa la posición void EnterName::decPosition() { - position_--; + --position_; position_ = std::max(position_, 0); } @@ -76,14 +76,14 @@ void EnterName::updateName() void EnterName::updateCharacterIndex() { // Rellena de espacios y marca como no usados - for (int i = 0; i < NAME_LENGHT; ++i) + for (size_t i = 0; i < NAME_LENGHT; ++i) { character_index_[i] = 0; position_has_been_used_[i] = false; } - // Coloca los índices en funcion de los caracteres que forman el nombre - for (int i = 0; i < (int)name_.size(); ++i) + // Coloca los índices en función de los caracteres que forman el nombre + for (size_t i = 0; i < name_.size(); ++i) { character_index_[i] = findIndex(name_.at(i)); position_has_been_used_[i] = true; @@ -91,15 +91,11 @@ void EnterName::updateCharacterIndex() } // Encuentra el indice de un caracter en "character_list_" -int EnterName::findIndex(char character) +int EnterName::findIndex(char character) const { - for (int i = 0; i < (int)character_list_.size(); ++i) - { - if (character == character_list_[i]) - { + for (size_t i = 0; i < character_list_.size(); ++i) + if (character == character_list_.at(i)) return i; - } - } return 0; } @@ -121,9 +117,7 @@ void EnterName::checkIfPositionHasBeenUsed() auto used = position_has_been_used_[position_]; if (!used && position_ > 0) - { character_index_[position_] = character_index_[position_ - 1]; - } position_has_been_used_[position_] = true; updateName(); diff --git a/source/enter_name.h b/source/enter_name.h index ec2262a..4f469a2 100644 --- a/source/enter_name.h +++ b/source/enter_name.h @@ -30,7 +30,7 @@ private: void updateCharacterIndex(); // Encuentra el indice de un caracter en "characterList" - int findIndex(char character); + int findIndex(char character) const; // Comprueba la posición y copia el caracter si es necesario void checkIfPositionHasBeenUsed(); diff --git a/source/game.cpp b/source/game.cpp index c6f30ed..a586b33 100644 --- a/source/game.cpp +++ b/source/game.cpp @@ -124,6 +124,7 @@ void Game::setResources() game_text_textures_.emplace_back(Resource::get()->getTexture("game_text_5000_points.png")); game_text_textures_.emplace_back(Resource::get()->getTexture("game_text_powerup.png")); game_text_textures_.emplace_back(Resource::get()->getTexture("game_text_one_hit.png")); + game_text_textures_.emplace_back(Resource::get()->getTexture("game_text_stop.png")); } // Texturas - Globos @@ -438,6 +439,20 @@ std::shared_ptr Game::createBalloon(float x, int y, BalloonType type, B return balloons_.back(); } +// Crea un globo a partir de otro globo +void Game::createChildBalloon(const std::shared_ptr &balloon, const std::string &direction) +{ + const float vx = direction == "LEFT" ? BALLOON_VELX_NEGATIVE : BALLOON_VELX_POSITIVE; + const auto lower_size = static_cast(static_cast(balloon->getSize()) - 1); + auto b = createBalloon(0, balloon->getPosY(), balloon->getType(), lower_size, vx, balloon_speed_, 0); + b->alignTo(balloon->getPosX() + (balloon->getWidth() / 2)); + b->setVelY(b->getType() == BalloonType::BALLOON ? -2.50f : vx * 2.0f); + if (balloon->isStopped()) + b->stop(); + if (balloon->isUsingReversedColor()) + b->useReverseColor(); +} + // Crea una PowerBall void Game::createPowerBall() { @@ -491,7 +506,6 @@ void Game::updateBalloonSpeed() // Explosiona un globo. Lo destruye y crea otros dos si es el caso void Game::popBalloon(std::shared_ptr balloon) { - // Aumenta el poder de la fase increaseStageCurrentPower(1); balloons_popped_++; @@ -503,29 +517,15 @@ void Game::popBalloon(std::shared_ptr balloon) } else { - const int size = static_cast(balloon->getSize()); - if (size == static_cast(BalloonSize::SIZE1)) + if (balloon->getSize() != BalloonSize::SIZE1) { - // Si es del tipo más pequeño, simplemente elimina el globo - explosions_->add(balloon->getPosX(), balloon->getPosY(), size); - balloon->pop(); + createChildBalloon(balloon, "LEFT"); + createChildBalloon(balloon, "RIGHT"); } - else - { - const auto lower_size = static_cast(size - 1); - // En cualquier otro caso, crea dos globos de un tipo inferior - auto balloon_left = createBalloon(0, balloon->getPosY(), balloon->getType(), lower_size, BALLOON_VELX_NEGATIVE, balloon_speed_, 0); - balloon_left->alignTo(balloon->getPosX() + (balloon->getWidth() / 2)); - balloon_left->setVelY(balloon_left->getType() == BalloonType::BALLOON ? -2.50f : BALLOON_VELX_NEGATIVE * 2.0f); - auto balloon_right = createBalloon(0, balloon->getPosY(), balloon->getType(), lower_size, BALLOON_VELX_POSITIVE, balloon_speed_, 0); - balloon_right->alignTo(balloon->getPosX() + (balloon->getWidth() / 2)); - balloon_right->setVelY(balloon_right->getType() == BalloonType::BALLOON ? -2.50f : BALLOON_VELX_NEGATIVE * 2.0f); - - // Elimina el globo - explosions_->add(balloon->getPosX(), balloon->getPosY(), size); - balloon->pop(); - } + // Agrega la explosión y elimina el globo + explosions_->add(balloon->getPosX(), balloon->getPosY(), static_cast(balloon->getSize())); + balloon->pop(); } // Recalcula el nivel de amenaza @@ -543,19 +543,15 @@ void Game::destroyBalloon(std::shared_ptr &balloon) case BalloonSize::SIZE4: score = BALLOON_SCORE[3] + (2 * BALLOON_SCORE[2]) + (4 * BALLOON_SCORE[1]) + (8 * BALLOON_SCORE[0]); break; - case BalloonSize::SIZE3: score = BALLOON_SCORE[2] + (2 * BALLOON_SCORE[1]) + (4 * BALLOON_SCORE[0]); break; - case BalloonSize::SIZE2: score = BALLOON_SCORE[1] + (2 * BALLOON_SCORE[0]); break; - case BalloonSize::SIZE1: score = BALLOON_SCORE[0]; break; - default: score = 0; break; @@ -563,9 +559,7 @@ void Game::destroyBalloon(std::shared_ptr &balloon) // Otorga los puntos correspondientes al globo for (auto &player : players_) - { player->addScore(score * player->getScoreMultiplier() * difficulty_score_multiplier_); - } updateHiScore(); // Aumenta el poder de la fase @@ -576,21 +570,14 @@ void Game::destroyBalloon(std::shared_ptr &balloon) // Destruye el globo explosions_->add(balloon->getPosX(), balloon->getPosY(), static_cast(balloon->getSize())); balloon->pop(); - - // Recalcula el nivel de amenaza - evaluateAndSetMenace(); } // Destruye todos los globos void Game::destroyAllBalloons() { for (auto &balloon : balloons_) - { if (balloon->canBeDestroyed()) - { destroyBalloon(balloon); - } - } balloon_deploy_counter_ = 300; JA_PlaySound(Resource::get()->getSound("powerball.wav")); @@ -599,29 +586,32 @@ void Game::destroyAllBalloons() } // Detiene todos los globos -void Game::stopAllBalloons(int time) +void Game::stopAllBalloons() { for (auto &balloon : balloons_) - { - if (balloon->isEnabled()) - { - balloon->setStop(true); - balloon->setStoppedTimer(time); - } - } + balloon->stop(); } // Pone en marcha todos los globos void Game::startAllBalloons() { for (auto &balloon : balloons_) - { - if ((balloon->isEnabled()) && (!balloon->isBeingCreated())) - { - balloon->setStop(false); - balloon->setStoppedTimer(0); - } - } + if (!balloon->isBeingCreated()) + balloon->start(); +} + +// Cambia el color de todos los globos +void Game::reverseColorsToAllBalloons() +{ + for (auto &balloon : balloons_) + balloon->useReverseColor(); +} + +// Cambia el color de todos los globos +void Game::normalColorsToAllBalloons() +{ + for (auto &balloon : balloons_) + balloon->useNormalColor(); } // Vacia del vector de globos los globos que ya no sirven @@ -637,15 +627,9 @@ void Game::freeBalloons() bool Game::checkPlayerBalloonCollision(std::shared_ptr &player) { for (auto &balloon : balloons_) - { if ((balloon->isEnabled()) && !(balloon->isStopped()) && !(balloon->isInvulnerable())) - { if (checkCollision(player->getCollider(), balloon->getCollider())) - { return true; - } - } - } return false; } @@ -654,9 +638,7 @@ bool Game::checkPlayerBalloonCollision(std::shared_ptr &player) void Game::checkPlayerItemCollision(std::shared_ptr &player) { if (!player->isPlaying()) - { return; - } for (auto &item : items_) { @@ -672,27 +654,24 @@ void Game::checkPlayerItemCollision(std::shared_ptr &player) createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (game_text_textures_[0]->getWidth() / 2), player->getPosY(), game_text_textures_[0]); break; } - case ItemType::GAVINA: { player->addScore(2500); createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (game_text_textures_[1]->getWidth() / 2), player->getPosY(), game_text_textures_[1]); break; } - case ItemType::PACMAR: { player->addScore(5000); createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (game_text_textures_[2]->getWidth() / 2), player->getPosY(), game_text_textures_[2]); break; } - case ItemType::CLOCK: { enableTimeStopItem(); + createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (game_text_textures_[5]->getWidth() / 2), player->getPosY(), game_text_textures_[5]); break; } - case ItemType::COFFEE: { if (player->getCoffees() == 2) @@ -707,7 +686,6 @@ void Game::checkPlayerItemCollision(std::shared_ptr &player) } break; } - case ItemType::COFFEE_MACHINE: { player->setPowerUp(); @@ -715,7 +693,6 @@ void Game::checkPlayerItemCollision(std::shared_ptr &player) createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (game_text_textures_[3]->getWidth() / 2), player->getPosY(), game_text_textures_[3]); break; } - default: break; } @@ -785,27 +762,15 @@ void Game::checkBulletBalloonCollision() void Game::moveBullets() { for (auto &bullet : bullets_) - { - if (bullet->isEnabled()) - { - if (bullet->move() == BulletMoveStatus::OUT) - { - getPlayer(bullet->getOwner())->decScoreMultiplier(); - } - } - } + if (bullet->move() == BulletMoveStatus::OUT) + getPlayer(bullet->getOwner())->decScoreMultiplier(); } // Pinta las balas activas void Game::renderBullets() { for (auto &bullet : bullets_) - { - if (bullet->isEnabled()) - { - bullet->render(); - } - } + bullet->render(); } // Crea un objeto bala @@ -818,22 +783,15 @@ void Game::createBullet(int x, int y, BulletType kind, bool powered_up, int owne void Game::freeBullets() { if (!bullets_.empty()) - { for (int i = bullets_.size() - 1; i >= 0; --i) - { if (!bullets_[i]->isEnabled()) - { bullets_.erase(bullets_.begin() + i); - } - } - } } // Actualiza los items void Game::updateItems() { for (auto &item : items_) - { if (item->isEnabled()) { item->update(); @@ -843,16 +801,13 @@ void Game::updateItems() screen_->shake(); } } - } } // Pinta los items activos void Game::renderItems() { for (auto &item : items_) - { item->render(); - } } // Devuelve un item al azar y luego segun sus probabilidades @@ -869,28 +824,24 @@ ItemType Game::dropItem() return ItemType::DISK; } break; - case 1: if (lucky_number < helper_.item_gavina_odds) { return ItemType::GAVINA; } break; - case 2: if (lucky_number < helper_.item_pacmar_odds) { return ItemType::GAVINA; } break; - case 3: if (lucky_number < helper_.item_clock_odds) { return ItemType::CLOCK; } break; - case 4: if (lucky_number < helper_.item_coffee_odds) { @@ -900,30 +851,22 @@ ItemType Game::dropItem() else { if (helper_.need_coffee) - { helper_.item_coffee_odds++; - } } break; - case 5: if (lucky_number < helper_.item_coffee_machine_odds) { helper_.item_coffee_machine_odds = ITEM_COFFEE_MACHINE_ODDS_; if (!coffee_machine_enabled_ && helper_.need_coffee_machine) - { return ItemType::COFFEE_MACHINE; - } } else { if (helper_.need_coffee_machine) - { helper_.item_coffee_machine_odds++; - } } break; - default: break; } @@ -941,15 +884,9 @@ void Game::createItem(ItemType type, float x, float y) void Game::freeItems() { if (!items_.empty()) - { for (int i = items_.size() - 1; i >= 0; --i) - { if (!items_[i]->isEnabled()) - { items_.erase(items_.begin() + i); - } - } - } } // Crea un objeto SpriteSmart para mostrar la puntuación al coger un objeto @@ -980,15 +917,9 @@ void Game::createItemScoreSprite(int x, int y, std::shared_ptr texture) void Game::freeSpriteSmarts() { if (!smart_sprites_.empty()) - { for (int i = smart_sprites_.size() - 1; i >= 0; --i) - { if (smart_sprites_[i]->hasFinished()) - { smart_sprites_.erase(smart_sprites_.begin() + i); - } - } - } } // Crea un SpriteSmart para arrojar el item café al recibir un impacto @@ -1018,18 +949,14 @@ void Game::throwCoffee(int x, int y) void Game::updateSpriteSmarts() { for (auto &ss : smart_sprites_) - { ss->update(); - } } // Pinta los SpriteSmarts activos void Game::renderSpriteSmarts() { for (auto &ss : smart_sprites_) - { ss->render(); - } } // Acciones a realizar cuando el jugador muere @@ -1052,20 +979,13 @@ void Game::killPlayer(std::shared_ptr &player) else { // Si no tiene cafes, muere - if (!demo_.enabled) - { - JA_PauseMusic(); - } - stopAllBalloons(10); + pauseMusic(); + stopAllBalloons(); JA_PlaySound(Resource::get()->getSound("player_collision.wav")); screen_->shake(); JA_PlaySound(Resource::get()->getSound("coffeeout.wav")); player->setStatusPlaying(PlayerStatus::DYING); - if (!demo_.enabled) - { - // En el modo DEMO ni se para la musica ni se añade la puntuación a la tabla - allPlayersAreNotPlaying() ? JA_StopMusic() : JA_ResumeMusic(); - } + allPlayersAreNotPlaying() ? stopMusic() : resumeMusic(); } } @@ -1076,60 +996,36 @@ void Game::evaluateAndSetMenace() { return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); }); } -// Obtiene el valor de la variable -int Game::getMenace() const -{ - return menace_current_; -} - -// Establece el valor de la variable -void Game::setTimeStopped(bool value) -{ - time_stopped_ = value; -} - -// Obtiene el valor de la variable -bool Game::isTimeStopped() const -{ - return time_stopped_; -} - -// Establece el valor de la variable -void Game::setTimeStoppedCounter(int value) -{ - time_stopped_counter_ = value; -} - -// Incrementa el valor de la variable -void Game::incTimeStoppedCounter(int value) -{ - time_stopped_counter_ += value; -} - // Actualiza y comprueba el valor de la variable -void Game::updateTimeStoppedCounter() +void Game::updateTimeStopped() { - if (isTimeStopped()) + if (time_stopped_counter_ > 0) { - if (time_stopped_counter_ > 0) + time_stopped_counter_--; + if (time_stopped_counter_ > 120) { - time_stopped_counter_--; - stopAllBalloons(TIME_STOPPED_COUNTER_); + if (time_stopped_counter_ % 30 == 0) + JA_PlaySound(Resource::get()->getSound("clock.wav")); } else { - disableTimeStopItem(); + if (time_stopped_counter_ % 15 == 0) + JA_PlaySound(Resource::get()->getSound("clock.wav")); + if (time_stopped_counter_ % 30 == 0) + normalColorsToAllBalloons(); + if (time_stopped_counter_ % 30 == 15) + reverseColorsToAllBalloons(); } } + else + disableTimeStopItem(); } // Actualiza la variable enemyDeployCounter void Game::updateBalloonDeployCounter() { if (balloon_deploy_counter_ > 0) - { --balloon_deploy_counter_; - } } // Actualiza el juego @@ -1149,9 +1045,7 @@ void Game::update() { // Incrementa el contador de la demo if (demo_.counter < TOTAL_DEMO_DATA) - { demo_.counter++; - } // Activa el fundido antes de acabar con los datos de la demo if (demo_.counter == TOTAL_DEMO_DATA - 200) @@ -1174,9 +1068,7 @@ void Game::update() // Incrementa el contador de la demo if (demo_.counter < TOTAL_DEMO_DATA) - { demo_.counter++; - } // Si se ha llenado el vector con datos, sale del programa else @@ -1229,7 +1121,7 @@ void Game::update() updateSpriteSmarts(); // Actualiza los contadores de estado y efectos - updateTimeStoppedCounter(); + updateTimeStopped(); updateBalloonDeployCounter(); // Actualiza el ayudante @@ -1273,9 +1165,7 @@ void Game::updateBackground() { // Si el juego está completado, se reduce la velocidad de las nubes if (game_completed_) - { balloons_popped_ = (balloons_popped_ > 400) ? (balloons_popped_ - 25) : 200; - } // Calcula la velocidad en función de los globos explotados y el total de globos a explotar para acabar el juego constexpr auto clouds_initial_speed = 0.05f; @@ -1337,9 +1227,7 @@ void Game::render() void Game::updateMenace() { if (game_completed_) - { return; - } const auto stage = balloon_formations_->getStage(current_stage_); const float percent = current_power_ / stage.power_to_complete; @@ -1364,33 +1252,7 @@ void Game::renderMessages() { // GetReady if (counter_ < STAGE_COUNTER_ && !demo_.enabled) - { text_nokia2_big_->write((int)get_ready_bitmap_path_[counter_], param.game.play_area.center_y - 8, lang::getText(75), -2); - } - - // Time Stopped - if (time_stopped_) - { - if (time_stopped_counter_ > 100 || time_stopped_counter_ % 10 > 4) - { - text_nokia2_->writeDX(TEXT_CENTER, param.game.play_area.center_x, param.game.play_area.first_quarter_y, lang::getText(36) + std::to_string(time_stopped_counter_ / 10), -1, no_color, 1, shdw_txt_color); - } - - if (time_stopped_counter_ > 100) - { - if (time_stopped_counter_ % 30 == 0) - { - JA_PlaySound(Resource::get()->getSound("clock.wav")); - } - } - else - { - if (time_stopped_counter_ % 15 == 0) - { - JA_PlaySound(Resource::get()->getSound("clock.wav")); - } - } - } // STAGE NUMBER if (stage_bitmap_counter_ < STAGE_COUNTER_) @@ -1399,20 +1261,24 @@ void Game::renderMessages() std::string text; if (stage_number == 10) - { // Ultima fase + { + // Ultima fase text = lang::getText(79); } else - { // X fases restantes + { + // X fases restantes text = std::to_string(11 - stage_number) + lang::getText(38); } if (!game_completed_) - { // Escribe el número de fases restantes + { + // Escribe el número de fases restantes text_nokia2_big_->writeDX(TEXT_CENTER, param.game.play_area.center_x, stage_bitmap_path_[stage_bitmap_counter_], text, -2, no_color, 2, shdw_txt_color); } else - { // Escribe el texto de juego completado + { + // Escribe el texto de juego completado text = lang::getText(50); text_nokia2_big_->writeDX(TEXT_CENTER, param.game.play_area.center_x, stage_bitmap_path_[stage_bitmap_counter_], text, -2, no_color, 1, shdw_txt_color); text_nokia2_->writeDX(TEXT_CENTER, param.game.play_area.center_x, stage_bitmap_path_[stage_bitmap_counter_] + text_nokia2_big_->getCharacterSize() + 2, lang::getText(76), -1, no_color, 1, shdw_txt_color); @@ -1423,25 +1289,17 @@ void Game::renderMessages() // Habilita el efecto del item de detener el tiempo void Game::enableTimeStopItem() { - stopAllBalloons(TIME_STOPPED_COUNTER_); - setTimeStopped(true); - incTimeStoppedCounter(TIME_STOPPED_COUNTER_); - if (JA_GetMusicState() == JA_MUSIC_PLAYING && !demo_.enabled) - { - JA_PauseMusic(); - } + stopAllBalloons(); + reverseColorsToAllBalloons(); + time_stopped_counter_ = TIME_STOPPED_COUNTER_; } // Deshabilita el efecto del item de detener el tiempo void Game::disableTimeStopItem() { - time_stopped_ = false; - setTimeStoppedCounter(0); + time_stopped_counter_ = 0; startAllBalloons(); - if (JA_GetMusicState() == JA_MUSIC_PAUSED && !demo_.enabled) - { - JA_ResumeMusic(); - } + normalColorsToAllBalloons(); } // Comprueba si la música ha de estar sonando @@ -1449,10 +1307,8 @@ void Game::checkMusicStatus() { // Si la música no está sonando if (JA_GetMusicState() == JA_MUSIC_INVALID || JA_GetMusicState() == JA_MUSIC_STOPPED) - { // Si se ha completado el juego o los jugadores han terminado, detiene la música game_completed_ || allPlayersAreGameOver() ? JA_StopMusic() : JA_PlayMusic(Resource::get()->getMusic("playing.ogg")); - } } // Bucle para el juego @@ -1491,9 +1347,7 @@ void Game::initPaths() // Vector con los valores del seno para 360 grados float sin[360]; for (int i = 0; i < 360; ++i) - { sin[i] = SDL_sinf((float)i * 3.14f / 180.0f); - } // Letrero de STAGE # constexpr auto first_part = STAGE_COUNTER_ / 4; // 50 @@ -1508,9 +1362,7 @@ void Game::initPaths() } for (int i = first_part; i < second_part; ++i) - { stage_bitmap_path_[i] = center_point; - } for (int i = second_part; i < STAGE_COUNTER_; ++i) { @@ -1536,9 +1388,7 @@ void Game::initPaths() } for (int i = first_part; i < second_part; ++i) - { get_ready_bitmap_path_[i] = (int)finish1; - } for (int i = second_part; i < STAGE_COUNTER_; ++i) { @@ -1552,9 +1402,7 @@ void Game::initPaths() void Game::updateGameCompleted() { if (game_completed_) - { game_completed_counter_++; - } if (game_completed_counter_ == GAME_COMPLETED_END_) { @@ -1581,9 +1429,7 @@ void Game::updateHelper() } } else - { helper_.need_coffee = helper_.need_coffee_machine = false; - } } // Comprueba si todos los jugadores han terminado de jugar @@ -1591,9 +1437,7 @@ bool Game::allPlayersAreWaitingOrGameOver() { auto success = true; for (const auto &player : players_) - { success &= player->isWaiting() || player->isGameOver(); - } return success; } @@ -1603,9 +1447,7 @@ bool Game::allPlayersAreGameOver() { auto success = true; for (const auto &player : players_) - { success &= player->isGameOver(); - } return success; } @@ -1615,9 +1457,7 @@ bool Game::allPlayersAreNotPlaying() { auto success = true; for (const auto &player : players_) - { success &= !player->isPlaying(); - } return success; } @@ -1642,10 +1482,7 @@ void Game::checkEvents() { case SDL_WINDOWEVENT_FOCUS_LOST: { - if (!demo_.enabled) - { - pause(true); - } + pause(!demo_.enabled); break; } @@ -1654,13 +1491,11 @@ void Game::checkEvents() pause(false); break; } - case SDL_WINDOWEVENT_SIZE_CHANGED: { reloadTextures(); break; } - default: break; } @@ -1671,28 +1506,27 @@ void Game::checkEvents() { switch (event.key.keysym.sym) { - // Crea una powerball - case SDLK_1: + case SDLK_1: // Crea una powerball { createPowerBall(); break; } - - // Crea dos globos gordos - case SDLK_2: + case SDLK_2: // Crea dos globos gordos { createTwoBigBalloons(); } break; - - // Activa el modo para pasar el juego automaticamente - case SDLK_3: + case SDLK_3: // Activa el modo para pasar el juego automaticamente { auto_pop_balloons_ = !auto_pop_balloons_; Notifier::get()->showText("auto_pop_balloons_ " + boolToString(auto_pop_balloons_)); break; } - + case SDLK_4: // Suelta un item + { + createItem(ItemType::CLOCK, players_.at(0)->getPosX(), players_.at(0)->getPosY() - 40); + break; + } default: break; } @@ -1705,27 +1539,17 @@ void Game::checkEvents() void Game::reloadTextures() { for (auto &texture : item_textures_) - { texture->reLoad(); - } for (auto &texture : balloon_textures_) - { texture->reLoad(); - } for (auto &textures : player_textures_) - { for (auto &texture : textures) - { texture->reLoad(); - } - } for (auto &texture : game_text_textures_) - { texture->reLoad(); - } bullet_texture_->reLoad(); background_->reloadTextures(); @@ -1881,7 +1705,6 @@ void Game::handleDemoMode() } // Procesa las entradas para un jugador específico durante el modo demo. -// Incluye movimientos (izquierda, derecha, sin movimiento) y disparos automáticos. void Game::handleDemoPlayerInput(const std::shared_ptr &player, int index) { const auto &demoData = demo_.data[index][demo_.counter]; @@ -2202,4 +2025,25 @@ void Game::createTwoBigBalloons() auto p = set.init[i]; createBalloon(p.x, p.y, p.type, p.size, p.vel_x, balloon_speed_, p.creation_counter); } +} + +// Pausa la música +void Game::pauseMusic() +{ + if (JA_GetMusicState() == JA_MUSIC_PLAYING && !demo_.enabled) + JA_PauseMusic(); +} + +// Reanuda la música +void Game::resumeMusic() +{ + if (JA_GetMusicState() == JA_MUSIC_PAUSED && !demo_.enabled) + JA_ResumeMusic(); +} + +// Detiene la música +void Game::stopMusic() +{ + if (!demo_.enabled) + JA_StopMusic(); } \ No newline at end of file diff --git a/source/game.h b/source/game.h index 5f625a1..72fcdca 100644 --- a/source/game.h +++ b/source/game.h @@ -72,7 +72,7 @@ private: static constexpr int GAME_COMPLETED_START_FADE_ = 500; static constexpr int GAME_COMPLETED_END_ = 700; static constexpr int GAME_OVER_COUNTER_ = 350; - static constexpr int TIME_STOPPED_COUNTER_ = 300; + static constexpr int TIME_STOPPED_COUNTER_ = 360; // Porcentaje de aparición de los objetos static constexpr int ITEM_POINTS_1_DISK_ODDS_ = 10; @@ -151,9 +151,9 @@ private: std::unique_ptr fade_; // Objeto para renderizar fades // Variables - HiScoreEntry hi_score_ = - HiScoreEntry(options.game.hi_score_table[0].name, - options.game.hi_score_table[0].score); // Máxima puntuación y nombre de quien la ostenta + HiScoreEntry hi_score_ = HiScoreEntry( + options.game.hi_score_table[0].name, + options.game.hi_score_table[0].score); // Máxima puntuación y nombre de quien la ostenta int current_stage_; // Indica la fase actual int last_stage_reached_; // Contiene el número de la última pantalla que se ha alcanzado @@ -166,7 +166,6 @@ private: bool hi_score_achieved_ = false; // Indica si se ha superado la puntuación máxima bool paused_ = false; // Indica si el juego está pausado (no se deberia de poder utilizar en el modo arcade) bool power_ball_enabled_ = false; // Indica si hay una powerball ya activa - bool time_stopped_ = false; // Indica si el tiempo está detenido float balloon_speed_; // Velocidad a la que se mueven los enemigos float default_balloon_speed_; // Velocidad base de los enemigos, sin incrementar float difficulty_score_multiplier_; // Multiplicador de puntos en función de la dificultad @@ -231,6 +230,9 @@ private: // Crea un globo nuevo en el vector de globos std::shared_ptr createBalloon(float x, int y, BalloonType type, BalloonSize size, float velx, float speed, int stopped_counter); + // Crea un globo a partir de otro globo + void createChildBalloon(const std::shared_ptr &balloon, const std::string &direction); + // Crea una PowerBall void createPowerBall(); @@ -250,11 +252,17 @@ private: void destroyAllBalloons(); // Detiene todos los globos - void stopAllBalloons(int time); + void stopAllBalloons(); // Pone en marcha todos los globos void startAllBalloons(); + // Cambia el color de todos los globos + void reverseColorsToAllBalloons(); + + // Cambia el color de todos los globos + void normalColorsToAllBalloons(); + // Vacia el vector de globos void freeBalloons(); @@ -315,26 +323,11 @@ private: // Calcula y establece el valor de amenaza en funcion de los globos activos void evaluateAndSetMenace(); - // Obtiene el valor de la variable - int getMenace() const; - - // Establece el valor de la variable - void setTimeStopped(bool value); - - // Obtiene el valor de la variable - bool isTimeStopped() const; - - // Establece el valor de la variable - void setTimeStoppedCounter(int value); - - // Incrementa el valor de la variable - void incTimeStoppedCounter(int value); - // Actualiza la variable EnemyDeployCounter void updateBalloonDeployCounter(); // Actualiza y comprueba el valor de la variable - void updateTimeStoppedCounter(); + void updateTimeStopped(); // Gestiona el nivel de amenaza void updateMenace(); @@ -342,6 +335,9 @@ private: // Actualiza el fondo void updateBackground(); + // Inicializa las variables que contienen puntos de ruta para mover objetos + void initPaths(); + // Pinta diferentes mensajes en la pantalla void renderMessages(); @@ -357,9 +353,6 @@ private: // Calcula el poder actual de los globos en pantalla int calculateScreenPower(); - // Inicializa las variables que contienen puntos de ruta para mover objetos - void initPaths(); - // Actualiza el tramo final de juego, una vez completado void updateGameCompleted(); @@ -415,7 +408,6 @@ private: void handleDemoMode(); // Procesa las entradas para un jugador específico durante el modo demo. - // Incluye movimientos (izquierda, derecha, sin movimiento) y disparos automáticos. void handleDemoPlayerInput(const std::shared_ptr &player, int index); // Maneja el disparo de un jugador, incluyendo la creación de balas y la gestión del tiempo de espera entre disparos. @@ -454,6 +446,15 @@ private: // Crea dos globos gordos void createTwoBigBalloons(); + // Pausa la música + void pauseMusic(); + + // Reanuda la música + void resumeMusic(); + + // Detiene la música + void stopMusic(); + public: // Constructor Game(int playerID, int current_stage, bool demo); diff --git a/source/item.cpp b/source/item.cpp index 7e6c7bb..792987a 100644 --- a/source/item.cpp +++ b/source/item.cpp @@ -44,7 +44,7 @@ Item::Item(ItemType type, float x, float y, SDL_Rect &play_area, std::shared_ptr } // Centra el objeto en la posición X -void Item::allignTo(int x) +void Item::alignTo(int x) { pos_x_ = static_cast(x - (width_ / 2)); diff --git a/source/item.h b/source/item.h index 8064c83..e7d24ec 100644 --- a/source/item.h +++ b/source/item.h @@ -64,7 +64,7 @@ public: ~Item() = default; // Centra el objeto en la posición X - void allignTo(int x); + void alignTo(int x); // Pinta el objeto en la pantalla void render(); diff --git a/source/moving_sprite.h b/source/moving_sprite.h index 2d8dde6..485705a 100644 --- a/source/moving_sprite.h +++ b/source/moving_sprite.h @@ -54,7 +54,7 @@ public: explicit MovingSprite(std::shared_ptr texture); // Destructor - ~MovingSprite() = default; + virtual ~MovingSprite() = default; // Actualiza las variables internas del objeto virtual void update(); diff --git a/source/sprite.h b/source/sprite.h index ddfdb71..d059437 100644 --- a/source/sprite.h +++ b/source/sprite.h @@ -20,7 +20,7 @@ public: explicit Sprite(std::shared_ptr); // Destructor - ~Sprite() = default; + virtual ~Sprite() = default; // Muestra el sprite por pantalla virtual void render();