diff --git a/CMakeLists.txt b/CMakeLists.txt index a5a910f..67e2d81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,8 @@ add_executable(LotoStatek main.cpp sources/Beam.cpp headers/Heart.hpp sources/Heart.cpp + headers/PowerUp.h + sources/PowerUp.cpp ) if(WIN32) diff --git a/assets/img/powerups/TripleShotPU.png b/assets/img/powerups/TripleShotPU.png new file mode 100644 index 0000000..c3fa917 Binary files /dev/null and b/assets/img/powerups/TripleShotPU.png differ diff --git a/assets/img/powerups/fireratePU.png b/assets/img/powerups/fireratePU.png new file mode 100644 index 0000000..de83337 Binary files /dev/null and b/assets/img/powerups/fireratePU.png differ diff --git a/assets/img/powerups/movingSpeedPU.png b/assets/img/powerups/movingSpeedPU.png new file mode 100644 index 0000000..28fb1d6 Binary files /dev/null and b/assets/img/powerups/movingSpeedPU.png differ diff --git a/headers/Heart.hpp b/headers/Heart.hpp index 14c785c..213e475 100644 --- a/headers/Heart.hpp +++ b/headers/Heart.hpp @@ -6,7 +6,7 @@ class Heart : public ObjectItem { public: - Heart(float x, float y, sf::Texture &texture); + Heart(float x, float y, sf::Texture &texture_); void update() override; }; diff --git a/headers/ObjectItem.hpp b/headers/ObjectItem.hpp index bfcdaee..f87d194 100644 --- a/headers/ObjectItem.hpp +++ b/headers/ObjectItem.hpp @@ -7,6 +7,7 @@ class ObjectItem { public: + virtual ~ObjectItem() = default; ObjectItem(float x, float y, sf::Texture &texture); sf::Sprite &getSprite(); bool getStatus(); diff --git a/headers/Plansza.h b/headers/Plansza.h index d1698ba..5b6ae1e 100644 --- a/headers/Plansza.h +++ b/headers/Plansza.h @@ -15,6 +15,7 @@ #include "AudioManager.h" #include "Plansza.h" #include "Heart.hpp" +#include "PowerUp.h" #include "Size.h" enum ships{ @@ -31,8 +32,10 @@ public: std::vector &getMeteors(); void spawn_meteor(); void spawn_hearts(); + void spawn_power_up(); void update_meteors(); void update_hearts(); + void update_power_ups(); void update(); void update_score(); void spawn_player(); @@ -56,6 +59,10 @@ private: sf::Font font; sf::Clock meteorSpawnClock; sf::Clock heartSpawnClock; + sf::Clock powerUpSpawnClock; + sf::Clock movingSpeedPUTimer; + sf::Clock fireratePUTimer; + sf::Clock tripleShotPUTimer; sf::Clock spawnClock; sf::Clock scoreClock; sf::Clock shooterSpawnClock; @@ -79,6 +86,9 @@ private: sf::Texture meteorTexture2; sf::Texture heartTexture; sf::Texture heartTextureGray; + sf::Texture movingSpeedPowerUpTexture; + sf::Texture fireratePowerUpTexture; + sf::Texture tripleShotPowerUpTexture; std::vector enemies; std::vector AEnemies; std::vector BEnemies; @@ -87,6 +97,7 @@ private: std::vector meteors; std::vector hearts; std::vector heartStats; + std::vector powerUps; bool gameOver = false; }; diff --git a/headers/Player.h b/headers/Player.h index 0e4823e..6c4ab63 100644 --- a/headers/Player.h +++ b/headers/Player.h @@ -29,6 +29,7 @@ public: void moveUp() override; void moveDown() override; void takeDamage(); + void setTripleShot(bool toogle); void update(); std::vector& getRockets(); @@ -44,6 +45,7 @@ private: sf::Clock immortalityClock; // Zegar kontrolujący czas nieśmiertelności float immortalityDuration = 1.5f; // Czas trwania nieśmiertelności w sec bool isImmortal = false; // flaga na immortal + bool tripleShot = false; // flaga na potrójny strzał }; diff --git a/headers/PowerUp.h b/headers/PowerUp.h new file mode 100644 index 0000000..e6f5d1d --- /dev/null +++ b/headers/PowerUp.h @@ -0,0 +1,25 @@ +#ifndef POWERUP_H +#define POWERUP_H +#include "ObjectItem.hpp" + +class PowerUp : public ObjectItem { +public: + enum Type { + movingSpeedUp, + firerateUp, + tripleShotUp + }; + + PowerUp(float x, float y, sf::Texture &texture, Type type); + + void update() override; + + Type getType() const { + return type_; + } + +private: + Type type_; +}; + +#endif //POWERUP_H diff --git a/sources/Heart.cpp b/sources/Heart.cpp index 4a61998..d1c295c 100644 --- a/sources/Heart.cpp +++ b/sources/Heart.cpp @@ -1,13 +1,11 @@ #include "../headers/Heart.hpp" Heart::Heart(float x, float y, sf::Texture &texture) : ObjectItem(x,y,texture) { - outOfBounds = false; - texture = texture; - sprite.setTexture(texture); + texture_ = texture; + sprite.setTexture(texture_); sprite.setOrigin(sprite.getLocalBounds().width / 2, sprite.getLocalBounds().height / 2); // wycentrowanie sprite sprite.setPosition(x, y); movingSpeed = 3.0f; -// sprite.scale(0.05f, 0.05f); position.x = x; position.y = y; rotationSpeed = 0; @@ -16,7 +14,6 @@ Heart::Heart(float x, float y, sf::Texture &texture) : ObjectItem(x,y,texture) { void Heart::update() { sprite.move(0.0f, movingSpeed); // przesunięcie sprajta position.y += int(movingSpeed); // przesunięcie pozycji -// sprite.rotate(rotationSpeed); // obracanie tym meteorkiem pięknym if(position.y > 900) { outOfBounds = true; // jeżeli wyszedł poza granice ekranu ustaw tą zmienną } diff --git a/sources/Meteor.cpp b/sources/Meteor.cpp index edbe41e..5bbe384 100644 --- a/sources/Meteor.cpp +++ b/sources/Meteor.cpp @@ -1,7 +1,6 @@ #include "../headers/Meteor.h" Meteor::Meteor(float x, float y, sf::Texture &texture) : ObjectItem(x, y, texture) { - outOfBounds = false; texture_ = texture; sprite.setTexture(texture); sprite.setOrigin(sprite.getLocalBounds().width / 2, sprite.getLocalBounds().height / 2); // wycentrowanie sprite diff --git a/sources/ObjectItem.cpp b/sources/ObjectItem.cpp index 4d80017..0023578 100644 --- a/sources/ObjectItem.cpp +++ b/sources/ObjectItem.cpp @@ -1,6 +1,7 @@ #include "../headers/ObjectItem.hpp" ObjectItem::ObjectItem(float x, float y, sf::Texture &texture) { + outOfBounds = false; Position position_ = {0,0}; position_.x = static_cast(x); position_.y = static_cast(y); diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 0e9c294..403bac0 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -21,8 +21,14 @@ Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::Render } else { playerTexture.loadFromFile("../assets/ship/Dreadnought-Base.png"); } + // Ładowanie tekstur itemów meteorTexture1.loadFromFile("../assets/img/meteors/meteor-1.png"); meteorTexture2.loadFromFile("../assets/img/meteors/meteor-2.png"); + heartTexture.loadFromFile("../assets/img/hearts/heart.png"); + heartTextureGray.loadFromFile("../assets/img/hearts/heart_gray.png"); + movingSpeedPowerUpTexture.loadFromFile("../assets/img/powerups/movingSpeedPU.png"); + fireratePowerUpTexture.loadFromFile("../assets/img/powerups/fireratePU.png"); + tripleShotPowerUpTexture.loadFromFile("../assets/img/powerups/TripleShotPU.png"); // Ładowanie tekstur wrogów enemyTexture.loadFromFile("../assets/img/enemy/enemy.png"); advancedEnemyTexture.loadFromFile("../assets/img/enemy/advanced_enemy.png"); @@ -50,12 +56,6 @@ Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::Render audioManager.loadSoundEffect("shoot_alt", "../assets/sounds/shoot_alt.ogg"); audioManager.loadSoundEffect("fail", "../assets/sounds/fail.mp3"); - meteorTexture1.loadFromFile("../assets/img/meteors/meteor-1.png"); - meteorTexture2.loadFromFile("../assets/img/meteors/meteor-2.png"); - - heartTexture.loadFromFile("../assets/img/hearts/heart.png"); - heartTextureGray.loadFromFile("../assets/img/hearts/heart_gray.png"); - heartStats.emplace_back(heartTexture); heartStats.emplace_back(heartTexture); heartStats.emplace_back(heartTexture); @@ -64,6 +64,7 @@ Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::Render heartStats[2].setPosition(495, 10); meteorSpawnClock.restart(); + powerUpSpawnClock.restart(); spawn_player(); spawnClock.restart(); @@ -71,7 +72,8 @@ Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::Render // TODO: Refactor tej metody bo rozrosła się za bardzo już void Plansza::update() { -// tło + srand(time(0)); + // tło background.update(); background.draw(*window); @@ -100,11 +102,11 @@ void Plansza::update() { // TODO: Przenieść obiekt dźwięku wewnątrz klasy Bullet if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) { ship->shoot(); - audioManager.playSoundEffect("shoot", 70.f); // Odtworzenie dźwięku wystrzału + // audioManager.playSoundEffect("shoot", 70.f); // Odtworzenie dźwięku wystrzału } if (sf::Mouse::isButtonPressed(sf::Mouse::Right)) { ship->alternate_shoot(); - audioManager.playSoundEffect("shoot_alt", 70.f); // Odtworzenie dźwięku dla alternatywnego strzału + // audioManager.playSoundEffect("shoot_alt", 70.f); // Odtworzenie dźwięku dla alternatywnego strzału } // generowanie nowego meteoru @@ -113,9 +115,10 @@ void Plansza::update() { // Sprawnowanie wszystkich rodzajów wrogów // spawn_meteor(); // spawn_hearts(); + spawn_power_up(); // spawn_enemy(); // spawn_advanced_enemy(); - spawn_wiazkowiec(); + // spawn_wiazkowiec(); // spawn_bomber(); // spawn_kamikadze(); @@ -130,6 +133,11 @@ void Plansza::update() { window->draw(heart.getSprite()); } + for (auto &powerUp: powerUps) { + powerUp.update(); + window->draw(powerUp.getSprite()); + } + for (auto &bullet: ship->getBullets()) { bullet.update(); window->draw(bullet.getSprite()); @@ -143,6 +151,7 @@ void Plansza::update() { // Sprawdzenie, czy meteory i pociski są poza granicami ekranu update_meteors(); update_hearts(); + update_power_ups(); ship->updateBullets(); window->draw(ship->getSprite()); @@ -162,6 +171,42 @@ void Plansza::update() { } } + // TODO: Dodać obsługę kilku różnych power-upów + + //////////////////////////////////////////////////////////////////////////////////////////////// + // Sprawdzenie kolizji z power-upem na prędkość poruszania się i zwiększenie prędkości statku + for (auto powerUpIt = powerUps.begin(); powerUpIt != powerUps.end();) { + if (ship->getSprite().getGlobalBounds().intersects(powerUpIt->getSprite().getGlobalBounds())) { + if (powerUpIt->getType() == PowerUp::movingSpeedUp) { + ship->setMovingSpeed(15.0f); + movingSpeedPUTimer.restart(); + } + if (powerUpIt->getType() == PowerUp::firerateUp) { + ship->setFirerate(100); + fireratePUTimer.restart(); + } + if (powerUpIt->getType() == PowerUp::tripleShotUp) { + ship->setTripleShot(true); + tripleShotPUTimer.restart(); + } + powerUpIt = powerUps.erase(powerUpIt); + } else { + ++powerUpIt; + } + } + + if (movingSpeedPUTimer.getElapsedTime().asSeconds() >= 5.0f) { + ship->setMovingSpeed(8.0f); + } + if (fireratePUTimer.getElapsedTime().asSeconds() >= 10.0f) { + ship->setFirerate(200); + } + if (tripleShotPUTimer.getElapsedTime().asSeconds() >= 5.0f) { + ship->setTripleShot(false); + } + ///////////////////////////////Koniec obsługi kolizji z power-upami////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + for (auto meteorIt = getMeteors().begin(); meteorIt != getMeteors().end();) { bool meteorHit = false; for (auto rocketIt = ship->getBullets().begin(); rocketIt != ship->getBullets().end();) { @@ -697,7 +742,6 @@ void Plansza::update() { } // Meteor-related niżej - void Plansza::update_meteors() { // usuwanie meteorów, które wyleciały poza ekran for (auto &meteor: meteors) { @@ -707,6 +751,23 @@ void Plansza::update_meteors() { } } +void Plansza::update_hearts() { + // usuwanie serduszek, które wyleciały poza ekran + for (auto& heart : hearts) { + if(heart.getStatus()) { + hearts.erase(hearts.begin()); + } + } +} + +void Plansza::update_power_ups() { + for (auto& power : powerUps) { + if(power.getStatus()) { + powerUps.erase(powerUps.begin()); + } + } +} + void Plansza::spawn_meteor() { if (meteorSpawnClock.getElapsedTime().asSeconds() > rand() % 10 + 1) { // randomowy spawn meteorytów od 10 do 1 sekundy if (meteors.size() < 5) { // jeśli jest mniej niż 5 meteorów na planszy @@ -721,14 +782,35 @@ void Plansza::spawn_meteor() { } void Plansza::spawn_hearts() { - if (heartSpawnClock.getElapsedTime().asSeconds() > rand() % 26 + 5) { // randomowy spawn meteorytów od 5 do 30 sekundy - if (hearts.size() < 5) { // jeśli jest mniej niż 5 meteorów na planszy + if (heartSpawnClock.getElapsedTime().asSeconds() > rand() % 26 + 5) { // randomowy spawn serduszek od 5 do 30 sekundy + if (hearts.size() < 5) { // jeśli jest mniej niż 5 serduszek na planszy hearts.emplace_back(RandomNumberGenerator::getRandomNumber(50, 499), -100, heartTexture); } heartSpawnClock.restart(); } } +void Plansza::spawn_power_up() { + if (powerUpSpawnClock.getElapsedTime().asSeconds() > 5) { + if (powerUps.size() < 2) { + auto powerUpRand = rand() % 3; + switch (powerUpRand) { + case 0: + powerUps.emplace_back(RandomNumberGenerator::getRandomNumber(50, 499), -100, movingSpeedPowerUpTexture, PowerUp::movingSpeedUp); + break; + case 1: + powerUps.emplace_back(RandomNumberGenerator::getRandomNumber(50, 499), -100, fireratePowerUpTexture, PowerUp::firerateUp); + break; + case 2: + powerUps.emplace_back(RandomNumberGenerator::getRandomNumber(50,499), -100, tripleShotPowerUpTexture, PowerUp::tripleShotUp); + } + + + } + powerUpSpawnClock.restart(); + } +} + void Plansza::spawn_player() { ship = Player::getInstance(static_cast(window->getSize().x) / 2, static_cast(window->getSize().y) - 100, this->playerTexture); ship->loadTexture(); @@ -776,7 +858,7 @@ void Plansza::spawn_kamikadze() { } void Plansza::spawn_wiazkowiec() { - if (WiazkowiecSpawnClock.getElapsedTime().asSeconds() >= 5) { // Spawn co 10 sekund + if (WiazkowiecSpawnClock.getElapsedTime().asSeconds() >= 50) { // Spawn co 10 sekund if (WEnemies.size() < 1) { int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); Wiazkowiec wiazkowiec(spawnX, -50, WiazkowiecTexture, window); @@ -788,16 +870,6 @@ void Plansza::spawn_wiazkowiec() { } } - -void Plansza::update_hearts() { - // usuwanie serduszek, które wyleciały poza ekran - for (auto& heart : hearts) { - if(heart.getStatus()) { - hearts.erase(hearts.begin()); - } - } -} - Size Plansza::getSize() { return size; } @@ -806,7 +878,6 @@ std::vector &Plansza::getMeteors() { return meteors; } -// TODO: naliczanie punktów za zabicie wrogów void Plansza::update_score() { if (scoreClock.getElapsedTime().asMilliseconds() > 500) { score++; diff --git a/sources/Player.cpp b/sources/Player.cpp index 7170b2f..26e505e 100644 --- a/sources/Player.cpp +++ b/sources/Player.cpp @@ -36,8 +36,16 @@ void Player::loadTexture() { void Player::shoot() { auto now = std::chrono::steady_clock::now(); if (std::chrono::duration_cast(now - lastShotTime).count() >= firerate) { - bullets.emplace_back(position.x, position.y, bulletTexture); - lastShotTime = now; + if (tripleShot == true) { + bullets.emplace_back(position.x - 40, position.y, bulletTexture); + bullets.emplace_back(position.x, position.y, bulletTexture); + bullets.emplace_back(position.x + 40, position.y, bulletTexture); + lastShotTime = now; + } + if (tripleShot == false) { + bullets.emplace_back(position.x, position.y, bulletTexture); + lastShotTime = now; + } } } @@ -79,6 +87,10 @@ void Player::takeDamage() { } } +void Player::setTripleShot(bool toogle) { + tripleShot = toogle; +} + void Player::setFirerate(unsigned int firerate) { this->firerate = firerate; } diff --git a/sources/PowerUp.cpp b/sources/PowerUp.cpp new file mode 100644 index 0000000..a8e3ff8 --- /dev/null +++ b/sources/PowerUp.cpp @@ -0,0 +1,21 @@ +#include "../headers/PowerUp.h" + +PowerUp::PowerUp(float x, float y, sf::Texture &texture, PowerUp::Type type): ObjectItem(x, y, texture) { + position.x = x; + position.y = y; + texture_ = texture; + sprite.setTexture(texture); + sprite.setOrigin(sprite.getLocalBounds().width / 2, sprite.getLocalBounds().height / 2); // wycentrowanie sprite + sprite.setScale(0.5f, 0.5f); + sprite.setPosition(x, y); + movingSpeed = 3.0f; + this->type_ = type; +} + +void PowerUp::update() { + sprite.move(0.0f, movingSpeed); // przesunięcie sprajta + position.y += int(movingSpeed); // przesunięcie pozycji + if(position.y > 900) { + outOfBounds = true; // jeżeli wyszedł poza granice ekranu ustaw tą zmienną + } +}