diff --git a/CMakeLists.txt b/CMakeLists.txt index 67e2d81..a1f4172 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,8 @@ add_executable(LotoStatek main.cpp sources/Heart.cpp headers/PowerUp.h sources/PowerUp.cpp + sources/Boss.cpp + headers/Boss.h ) if(WIN32) diff --git a/assets/img/wiazka/wiazka.png b/assets/img/wiazka/wiazka.png deleted file mode 100644 index a70f3f0..0000000 Binary files a/assets/img/wiazka/wiazka.png and /dev/null differ diff --git a/headers/Boss.h b/headers/Boss.h new file mode 100644 index 0000000..b8c2281 --- /dev/null +++ b/headers/Boss.h @@ -0,0 +1,63 @@ +#ifndef BOSS_H +#define BOSS_H + +#include "Actor.h" +#include "Bullet.h" +#include "Beam.h" +#include +#include + +enum class BossDirection { + Up, + Down, + Left, + Right +}; + +class Boss : public Actor { +public: + Boss(int x, int y, const sf::Texture &bossTexture, const sf::Texture &bulletTexture, sf::Texture BombaTexture, + sf::RenderWindow *window); + + void moveLeft() override; + void moveRight() override; + void moveUp() override; + void moveDown() override; + + + + void shoot() override; + void dropBomb(); + void shootLaser(); + void move(float deltaX, float deltaY) override; + void update(); + void takeDamage(); + bool isAlive() const; + std::vector& getBullets() { return bullets; } + std::vector& getBombs() { return bombs; } + +private: + float movementSpeed = 1.5f; + BossDirection direction = BossDirection::Down; + + sf::Clock shootClock; + sf::Clock bombClock; + sf::Clock laserClock; + sf::Clock directionClock; + sf::Clock beamDurationClock; + float beamDuration = 1.0f; + + sf::Texture bulletTexture; + sf::Texture BombaTexture; + sf::Texture beamTexture; + sf::RenderWindow* window; + Beam* laserBeam = nullptr; + + std::vector bullets; + std::vector bombs; + + void setRandomDirection(); + void handleBounds(); +}; + +#endif // BOSS_H diff --git a/headers/Plansza.h b/headers/Plansza.h index 5365dd8..47e00f4 100644 --- a/headers/Plansza.h +++ b/headers/Plansza.h @@ -17,6 +17,7 @@ #include "Heart.hpp" #include "PowerUp.h" #include "Size.h" +#include "Boss.h" enum ships{ nova, @@ -49,10 +50,14 @@ public: void spawn_enemy(); void spawn_advanced_enemy(); void spawn_wiazkowiec(); + + void spawn_boss(); + void spawn_bomber(); void spawn_kamikadze(); ~Plansza() { delete ship; // usuwanie wskaźnika ship + delete boss; // Usuwanie wskaźnika bossa } static ships selectedShip; @@ -86,6 +91,7 @@ private: sf::Texture advancedEnemyTexture; sf::Texture BomberEnemyTexture; sf::Texture BombaTexture; + sf::Texture BossTexture; sf::Texture KamikadzeTexture; sf::Texture WiazkowiecTexture; sf::Texture WiazkaTexture; @@ -105,6 +111,9 @@ private: std::vector hearts; std::vector heartStats; std::vector powerUps; + Boss* boss = nullptr; // Wskaźnik na bossa + sf::Clock bossSpawnClock; // Zegar do spawnowania bossa + bool bossSpawned = false; // Flaga informująca, czy boss został już zespawnowany bool gameOver = false; }; diff --git a/sources/Boss.cpp b/sources/Boss.cpp new file mode 100644 index 0000000..e9fea30 --- /dev/null +++ b/sources/Boss.cpp @@ -0,0 +1,149 @@ +#include "../headers/Boss.h" +#include +#include +#include "../headers/RandomNumberGenerator.h" + +Boss::Boss(int x, int y, const sf::Texture& bossTexture, const sf::Texture& bulletTexture, const sf::Texture BombaTexture, sf::RenderWindow* window) + : Actor(x, y, bossTexture), bulletTexture(bulletTexture), BombaTexture(BombaTexture), window(window) { + try { + beamTexture.loadFromFile("../assets/img/wiazka/laser.png"); + } catch (std::exception& e) { + std::cerr << "Failed to load textures: " << e.what() << std::endl; + exit(-500); + } + hp = 100; + firerate = 2000; + +} + +void Boss::shoot() { + if (shootClock.getElapsedTime().asMilliseconds() >= firerate) { + Bullet leftBullet(position.x - 20, position.y, bulletTexture); + leftBullet.setSpeed(5.0f); + Bullet centerBullet(position.x, position.y, bulletTexture); + centerBullet.setSpeed(5.0f); + Bullet rightBullet(position.x + 20, position.y, bulletTexture); + rightBullet.setSpeed(5.0f); + bullets.push_back(std::move(leftBullet)); + bullets.push_back(std::move(centerBullet)); + bullets.push_back(std::move(rightBullet)); + std::cout << "Strzal lezy" << std::endl; + shootClock.restart(); + } +} + +void Boss::dropBomb() { + if (bombClock.getElapsedTime().asMilliseconds() >= 5000) { + Bullet Bomb(position.x, position.y, BombaTexture); + Bomb.setSpeed(0.1f); + bullets.emplace_back(std::move(Bomb)); // Można zmienić na bombę + std::cout << "Bombka lezy" << std::endl; + bombClock.restart(); + } +} + +void Boss::shootLaser() { + if (!laserBeam && laserClock.getElapsedTime().asSeconds() >= 5.0f) { + laserBeam = new Beam(position.x, position.y, beamTexture); + beamDurationClock.restart(); + laserClock.restart(); + } + + if (laserBeam) { + window->draw(laserBeam->getSprite()); + std::cout << "Laser beam shooted" << std::endl; + + if (beamDurationClock.getElapsedTime().asSeconds() >= beamDuration) { + delete laserBeam; + laserBeam = nullptr; + } + } +} + + +void Boss::move(float deltaX, float deltaY) { + actorSprite.move(deltaX, deltaY); + position.x += static_cast(deltaX); + position.y += static_cast(deltaY); + handleBounds(); +} + +void Boss::update() { + if (directionClock.getElapsedTime().asSeconds() >= 3.0f) { + setRandomDirection(); + directionClock.restart(); + } + + switch (direction) { + case BossDirection::Up: move(0, -movementSpeed); break; + case BossDirection::Down: move(0, movementSpeed); break; + case BossDirection::Left: move(-movementSpeed, 0); break; + case BossDirection::Right: move(movementSpeed, 0); break; + } + + shoot(); + dropBomb(); + shootLaser(); + + // Aktualizacja pocisków + for (auto it = bullets.begin(); it != bullets.end();) { + it->update(); + window->draw(it->getSprite()); + if (it->isOutOfBounds()) { + it = bullets.erase(it); + } else { + ++it; + } + } + + // Aktualizacja bomb + for (auto it = bombs.begin(); it != bombs.end();) { + it->update(); + window->draw(it->getSprite()); + if (it->isOutOfBounds()) { + it = bombs.erase(it); + } else { + ++it; + } + } +} + +void Boss::moveLeft() { + move(-movementSpeed, 0.0f); +} + +void Boss::moveRight() { + move(movementSpeed, 0.0f); +} + +void Boss::moveUp() { + move(0.0f, -movementSpeed); +} + +void Boss::moveDown() { + move(0.0f, movementSpeed); +} + + +void Boss::takeDamage() { + if (--hp <= 0) { + hp = 0; + } +} + +bool Boss::isAlive() const { + return hp > 0; +} + +void Boss::setRandomDirection() { + int randomValue = RandomNumberGenerator::getRandomNumber(0, 3); + direction = static_cast(randomValue); +} + + +void Boss::handleBounds() { + if (position.x <= 0) direction = BossDirection::Right; + if (position.x >= 300) direction = BossDirection::Left; + if (position.y <= 0) direction = BossDirection::Down; + if (position.y >= 300) direction = BossDirection::Up; +} diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 84b6f5c..d34184f 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -36,11 +36,21 @@ Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::Render KamikadzeTexture.loadFromFile("../assets/img/enemy/kamikadze.png"); BombaTexture.loadFromFile("../assets/img/bullets/bomba.png"); WiazkowiecTexture.loadFromFile("../assets/img/enemy/wiazkowiec.png"); + enemyBulletTexture.loadFromFile("../assets/img/bullets/enemy_bullet.png"); } catch (std::exception &e) { std::cerr << "Failed to load textures: " << e.what() << std::endl; exit(-500); } + try { + // ... + BossTexture.loadFromFile("../assets/img/boss/boss.png"); + } catch (std::exception &e) { + std::cerr << "Failed to load boss texture: " << e.what() << std::endl; + exit(-500); + } + + score = 0; // Wczytywanie czcionki dla licznika punktów @@ -115,11 +125,12 @@ void Plansza::update() { spawn_meteor(); spawn_hearts(); spawn_power_up(); - spawn_enemy(); - spawn_advanced_enemy(); - spawn_wiazkowiec(); - spawn_bomber(); - spawn_kamikadze(); + // spawn_enemy(); + // spawn_advanced_enemy(); + // spawn_wiazkowiec(); + // spawn_bomber(); + // spawn_kamikadze(); + spawn_boss(); // utrzymanie meteorów i pocisków w ruchu for (auto &meteor: meteors) { @@ -364,6 +375,55 @@ void Plansza::update() { } } + // Aktualizacja bossa + if (boss && boss->isAlive()) { + boss->update(); + window->draw(boss->getSprite()); + + // Kolizje bossa z pociskami + for (auto bulletIt = ship->getBullets().begin(); bulletIt != ship->getBullets().end();) { + if (boss->getSprite().getGlobalBounds().intersects(bulletIt->getSprite().getGlobalBounds())) { + boss->takeDamage(); + bulletIt = ship->getBullets().erase(bulletIt); + } else { + ++bulletIt; + } + } + + // Kolizja bossa z graczem + if (ship->getSprite().getGlobalBounds().intersects(boss->getSprite().getGlobalBounds())) { + ship->takeDamage(); + } + } else if (bossSpawned && (!boss || !boss->isAlive())) { + std::cout << "Boss defeated!" << std::endl; + delete boss; + boss = nullptr; + bossSpawned = false; // Resetowanie flagi, jeśli boss został pokonany + } + + // Obsługa pocisków bossa + if (boss && boss->isAlive()) { + for (auto it = boss->getBullets().begin(); it != boss->getBullets().end();) { + if (ship->getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + ship->takeDamage(); + it = boss->getBullets().erase(it); // Usuwanie pocisku po trafieniu + } else { + ++it; + } + } + + // Obsługa bomb bossa + for (auto it = boss->getBombs().begin(); it != boss->getBombs().end();) { + if (ship->getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + ship->takeDamage(); + it = boss->getBombs().erase(it); // Usuwanie bomby po trafieniu + } else { + ++it; + } + } + + } + for (auto &enemy: enemies) { enemy.shoot(); @@ -403,6 +463,7 @@ void Plansza::update() { } } + for (auto &bomberEnemy: BEnemies) { for (auto it = bomberEnemy.getBullets().begin(); it != bomberEnemy.getBullets().end();) { bool bulletDestroyed = false; @@ -819,7 +880,7 @@ void Plansza::spawn_kamikadze() { } void Plansza::spawn_wiazkowiec() { - if (WiazkowiecSpawnClock.getElapsedTime().asSeconds() >= 50) { // Spawn co 10 sekund + if (WiazkowiecSpawnClock.getElapsedTime().asSeconds() >= 3) { // Spawn co 10 sekund if (WEnemies.size() < 1) { int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); Wiazkowiec wiazkowiec(spawnX, -50, WiazkowiecTexture, window); @@ -831,6 +892,15 @@ void Plansza::spawn_wiazkowiec() { } } +void Plansza::spawn_boss() { + if (!bossSpawned && bossSpawnClock.getElapsedTime().asSeconds() >= 3) { // Spawn po 60 sekundach + boss = new Boss(size.width / 2, -100, BossTexture, enemyBulletTexture, BombaTexture, window); + bossSpawned = true; + std::cout << "Boss spawned!" << std::endl; + } +} + + Size Plansza::getSize() { return size; } @@ -893,4 +963,5 @@ void Plansza::check_Meteor_collisions() { } ships Plansza::selectedShip = none; -unsigned int Plansza::score = 0; \ No newline at end of file +unsigned int Plansza::score = 0; +