diff --git a/assets/img/enemy/kamikadze.png b/assets/img/enemy/kamikadze.png new file mode 100644 index 0000000..e8fe1a6 Binary files /dev/null and b/assets/img/enemy/kamikadze.png differ diff --git a/headers/Kamikadze.h b/headers/Kamikadze.h index 5fa494c..1783fcd 100644 --- a/headers/Kamikadze.h +++ b/headers/Kamikadze.h @@ -1,8 +1,45 @@ -// -// Created by k on 11.12.2024. -// - #ifndef KAMIKADZE_H #define KAMIKADZE_H +#include "Enemy.h" +#include "Actor.h" +#include "Player.h" +enum class DirectionK { + Up, + Down, + Left, + Right +}; + +class Kamikadze : public Actor { +public: + Kamikadze(int x, int y, const sf::Texture& texture); + + void move(float deltaX, float deltaY) override; + void moveLeft() override; + void moveRight() override; + void moveUp() override; + void moveDown() override; + void setRandomDirection(); + void shoot() override; + + void update(const sf::Vector2f& playerPosition); + + bool isAlive() const; + void takeDamage(); + void updateDirection(); + + void followPlayer(const sf::Vector2f &playerPosition); + + void explode(const sf::Vector2f &playerPosition, bool &playerHit); + +private: + bool exploding = false; // Czy kamikadze obecnie eksploduje + sf::Clock explosionClock; + sf::Clock shootClock; + float movementSpeed = 2.0f; + bool alive = true; + DirectionK direction = DirectionK::Down; +}; + #endif //KAMIKADZE_H diff --git a/headers/Plansza.h b/headers/Plansza.h index b29e586..551c0d0 100644 --- a/headers/Plansza.h +++ b/headers/Plansza.h @@ -5,6 +5,7 @@ #include "Enemy.h" #include "AdvancedEnemy.h" #include "Bomber.h" +#include "Kamikadze.h" #include "RandomNumberGenerator.h" #include "SFML/System/Clock.hpp" #include "SFML/Graphics/RenderWindow.hpp" @@ -33,6 +34,7 @@ public: void spawn_advanced_enemy(); void spawn_wiazkowiec(); void spawn_bomber(); + void spawn_kamikadze(); private: Size size; @@ -49,14 +51,17 @@ private: sf::Texture enemyTexture; sf::Texture advancedEnemyTexture; sf::Texture BomberEnemyTexture; + sf::Texture KamikadzeTexture; sf::Clock spawnClock; sf::Clock shooterSpawnClock; std::vector enemies; std::vector AEnemies; std::vector BEnemies; + std::vector KEnemies; sf::Clock enemySpawnClock; sf::Clock AenemySpawnClock; sf::Clock BomberSpawnClock; + sf::Clock KamikadzeSpawnClock; std::vector meteors; sf::RenderWindow *window; }; diff --git a/sources/Kamikadze.cpp b/sources/Kamikadze.cpp index 2fcec76..bd8f05c 100644 --- a/sources/Kamikadze.cpp +++ b/sources/Kamikadze.cpp @@ -1,3 +1,126 @@ -// -// Created by k on 11.12.2024. -// +#include "../headers/Kamikadze.h" +#include "../headers/Bullet.h" +#include + +Kamikadze::Kamikadze(int x, int y, const sf::Texture& texture) : Actor(x, y, texture) { + actorSprite.setTexture(texture); + hp = 3; // 3 punkty życia + moving_speed = 2.0f; // Prędkość +} + +void Kamikadze::shoot(){} + +// Losuje losowy kierunek dla Bombera +void Kamikadze::setRandomDirection() { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dist(0, 3); + + int randomDirection = dist(gen); + + // Zapobieganie wyjscia poza ekran + switch (randomDirection) { + case 0: + if (position.y > 0) direction = DirectionK::Up; + break; + case 1: + if (position.y < 800) direction = DirectionK::Down; + break; + case 2: + if (position.x > 0) direction = DirectionK::Left; + break; + case 3: + if (position.x < 1200) direction = DirectionK::Right; + break; + } +} + + +void Kamikadze::updateDirection() { + // Zmieniamy kierunek przeciwnika, gdy dotrze do krawędzi + if (position.y <= 0) { + direction = DirectionK::Down; + } else if (position.y >= 800) { + direction = DirectionK::Up; + } + + // logika dla kierunku lewo/prawo + if (position.x <= 0) { + direction = DirectionK::Right; + } else if (position.x >= 1200) { + direction = DirectionK::Left; + } +} + +void Kamikadze::followPlayer(const sf::Vector2f& playerPosition) { + // Oblicz różnicę w pozycjach + float diffX = playerPosition.x - position.x; + float diffY = playerPosition.y - position.y; + + // Normalizacja wektora (skrócenie kierunku do jednostkowego) + float magnitude = std::sqrt(diffX * diffX + diffY * diffY); + if (magnitude != 0) { + diffX /= magnitude; + diffY /= magnitude; + + // Aktualizacja pozycji Kamikadze w kierunku gracza z uwzględnieniem prędkości + position.x += diffX * movementSpeed; + position.y += diffY * movementSpeed; + } else { + // Jeśli Kamikadze jest dokładnie na pozycji gracza, zatrzymaj jego ruch + movementSpeed = 0.0f; + } +} + +void Kamikadze::explode(const sf::Vector2f& playerPosition, bool& playerHit) { + if (!exploding) { + // Kamikadze rozpoczyna eksplozję + exploding = true; + explosionClock.restart(); + movementSpeed = 0.0f; // Zatrzymaj ruch + + // Sprawdź, czy gracz jest w obszarze eksplozji + const float explosionRange = 50.0f; // Zakładając promień wybuchu + sf::Vector2f diff = playerPosition - sf::Vector2f(static_cast(position.x), static_cast(position.y)); + float distance = std::sqrt(diff.x * diff.x + diff.y * diff.y); + + if (distance <= explosionRange) { + playerHit = true; // Gracz został trafiony + } + } + + // Po zakończeniu eksplozji, Kamikadze umiera + if (exploding && explosionClock.getElapsedTime().asSeconds() >= 0.5f) { // 0.5 sekundy + alive = false; + } +} + +void Kamikadze::move(float deltaX, float deltaY) { + actorSprite.move(deltaX, deltaY); + position.x += static_cast(deltaX); + position.y += static_cast(deltaY); +} + +void Kamikadze::moveLeft() { move(-moving_speed, 0.0f); } +void Kamikadze::moveRight() { move(moving_speed, 0.0f); } +void Kamikadze::moveUp() { move(0.0f, -moving_speed); } +void Kamikadze::moveDown() { move(0.0f, moving_speed); } + +void Kamikadze::update(const sf::Vector2f& playerPosition) { + if (alive && !exploding) { + // Podążaj za graczem, dopóki Kamikadze jest żywy i nie eksploduje + followPlayer(playerPosition); + actorSprite.setPosition(position.x, position.y); // Aktualizuj sprite + } +} + + +bool Kamikadze::isAlive() const { + return alive; +} + +void Kamikadze::takeDamage() { + if (--hp <= 0) { + alive = false; + } +} \ No newline at end of file diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 15beee7..9383785 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -42,6 +42,10 @@ Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::Render std::cerr << "Failed to load advanced enemy texture!" << std::endl; exit(-1); } + if (!KamikadzeTexture.loadFromFile("../assets/img/enemy/kamikadze.png")) { + std::cerr << "Failed to load advanced enemy texture!" << std::endl; + exit(-1); + } if (!BombaTexture.loadFromFile("../assets/img/bullets/bomba.png")) { std::cerr << "Failed to load BombaTexture!" << std::endl; exit(-1); @@ -93,6 +97,7 @@ void Plansza::update() { spawn_advanced_enemy(); //spawn_wiazkowiec(); spawn_bomber(); + spawn_kamikadze(); // utrzymanie meteorów i pocisków w ruchu for (auto& meteor : getMeteors()) { @@ -258,6 +263,35 @@ void Plansza::update() { } + for (auto it = KEnemies.begin(); it != KEnemies.end();) { + sf::Vector2f playerPosition = ship.getSprite().getPosition(); // Pozycja gracza + bool playerHit = false; + + // Aktualizacja ruchu Kamikadze + + it->update(playerPosition); + + // Sprawdź kolizję z graczem + if (ship.getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + it->explode(playerPosition, playerHit); + + if (playerHit) { + ship.takeDamage(); // Gracz traci punkt życia + } + } + + // Rysuj Kamikadze na ekranie + if (it->isAlive()) { + window->draw(it->getSprite()); + ++it; + } else { + // Usuń, jeśli Kamikadze już nie żyje + std::cout << "Kamikadze has exploded!" << std::endl; + it = KEnemies.erase(it); + } + } + + // Obsługa pocisków zaawansowanych przeciwników for (auto& aEnemy : AEnemies) { for (auto it = aEnemy.getBullets().begin(); it != aEnemy.getBullets().end();) { @@ -389,12 +423,31 @@ void Plansza::update() { } } if (hit && !bomberIt->isAlive()) { - bomberIt = BEnemies.erase(bomberIt); // Usunięcie przeciwnika AdvancedEnemy + bomberIt = BEnemies.erase(bomberIt); // Usunięcie przeciwnika Bomber } else { ++bomberIt; } } + for (auto kamikadzeIt = KEnemies.begin(); kamikadzeIt != KEnemies.end();) { + bool hit = false; + for (auto bulletIt = ship.getBullets().begin(); bulletIt != ship.getBullets().end();) { + if (kamikadzeIt->getSprite().getGlobalBounds().intersects(bulletIt->getSprite().getGlobalBounds())) { + bulletIt = ship.getBullets().erase(bulletIt); + kamikadzeIt->takeDamage(); + hit = true; + break; + } else { + ++bulletIt; + } + } + if (hit && !kamikadzeIt->isAlive()) { + kamikadzeIt = KEnemies.erase(kamikadzeIt); // Usunięcie przeciwnika Kamikadze + } else { + ++kamikadzeIt; + } + } + //oblsuga dla rakiety @@ -455,6 +508,25 @@ void Plansza::update() { } } + for (auto kamikadzeIt = KEnemies.begin(); kamikadzeIt != KEnemies.end();) { + bool hit = false; + for (auto rocketIt = ship.getRockets().begin(); rocketIt != ship.getRockets().end();) { + if (kamikadzeIt->getSprite().getGlobalBounds().intersects(rocketIt->getSprite().getGlobalBounds())) { + rocketIt = ship.getRockets().erase(rocketIt); + kamikadzeIt->takeDamage(); + hit = true; + break; + } else { + ++rocketIt; + } + } + if (hit && !kamikadzeIt->isAlive()) { + kamikadzeIt = KEnemies.erase(kamikadzeIt); + } else { + ++kamikadzeIt; + } + } + } @@ -486,7 +558,7 @@ void Plansza::spawn_enemy() { if (enemySpawnClock.getElapsedTime().asSeconds() >= 110) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); enemies.emplace_back(spawnX, -50, enemyTexture); - + std::cout << "Spawned Basic Enemy at X: " << spawnX << std::endl; enemySpawnClock.restart(); } @@ -502,7 +574,7 @@ void Plansza::spawn_advanced_enemy() { } void Plansza::spawn_bomber() { - if (BomberSpawnClock.getElapsedTime().asSeconds() >= 10) { // Spawn co 10 sekund + if (BomberSpawnClock.getElapsedTime().asSeconds() >= 100) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); BEnemies.emplace_back(spawnX, -50, BomberEnemyTexture, BombaTexture); std::cout << "Spawned Bomber Enemy at X: " << spawnX << std::endl; @@ -510,6 +582,15 @@ void Plansza::spawn_bomber() { } } +void Plansza::spawn_kamikadze() { + if (KamikadzeSpawnClock.getElapsedTime().asSeconds() >= 5) { // Spawn co 10 sekund + int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); + KEnemies.emplace_back(spawnX, -50, KamikadzeTexture); + std::cout << "Spawned Kamikadze Enemy at X: " << spawnX << std::endl; + KamikadzeSpawnClock.restart(); + } +} +