diff --git a/CMakeLists.txt b/CMakeLists.txt index 6eacb45..522c937 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,20 @@ add_executable(LotoStatek main.cpp headers/Size.h headers/Position.h headers/ObjectItem.hpp - sources/ObjectItem.cpp) + sources/ObjectItem.cpp + sources/Enemy.cpp + headers/Enemy.h + headers/AdvancedEnemy.h + sources/AdvancedEnemy.cpp + headers/Bomber.h + sources/Bomber.cpp + headers/Kamikadze.h + sources/Kamikadze.cpp + headers/wiazkowiec.h + sources/Wiazkowiec.cpp + headers/Beam.h + sources/Beam.cpp +) if(WIN32) set(SFML_ROOT "${CMAKE_SOURCE_DIR}/lib/SFML") diff --git a/assets/img/bullets/bomba.png b/assets/img/bullets/bomba.png new file mode 100644 index 0000000..6f09bde Binary files /dev/null and b/assets/img/bullets/bomba.png differ diff --git a/assets/img/bullets/enemy_bullet.png b/assets/img/bullets/enemy_bullet.png new file mode 100644 index 0000000..5574a54 Binary files /dev/null and b/assets/img/bullets/enemy_bullet.png differ diff --git a/assets/img/enemy/advanced_enemy.png b/assets/img/enemy/advanced_enemy.png new file mode 100644 index 0000000..12fad0b Binary files /dev/null and b/assets/img/enemy/advanced_enemy.png differ diff --git a/assets/img/enemy/bomber.png b/assets/img/enemy/bomber.png new file mode 100644 index 0000000..836259c Binary files /dev/null and b/assets/img/enemy/bomber.png differ diff --git a/assets/img/enemy/enemy.png b/assets/img/enemy/enemy.png new file mode 100644 index 0000000..5ae8acc Binary files /dev/null and b/assets/img/enemy/enemy.png differ 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/assets/img/enemy/wiazkowiec.png b/assets/img/enemy/wiazkowiec.png new file mode 100644 index 0000000..bdfa19e Binary files /dev/null and b/assets/img/enemy/wiazkowiec.png differ diff --git a/assets/img/wiazka/wiazka.png b/assets/img/wiazka/wiazka.png new file mode 100644 index 0000000..a70f3f0 Binary files /dev/null and b/assets/img/wiazka/wiazka.png differ diff --git a/headers/Actor.h b/headers/Actor.h index 7fc1ec6..fe05f3a 100644 --- a/headers/Actor.h +++ b/headers/Actor.h @@ -9,7 +9,7 @@ class Actor { public: - Actor(int x, int y, std::string path); + Actor(int x, int y, const sf::Texture& texture); void loadTexture(std::string path); diff --git a/headers/AdvancedEnemy.h b/headers/AdvancedEnemy.h new file mode 100644 index 0000000..769fa74 --- /dev/null +++ b/headers/AdvancedEnemy.h @@ -0,0 +1,39 @@ +#ifndef ADVANCED_ENEMY_H +#define ADVANCED_ENEMY_H + +#include "Enemy.h" + +#include + +enum class DirectionA { + Up, + Down, + Left, + Right +}; + +class AdvancedEnemy : public Actor { +public: + AdvancedEnemy(int x, int y, const sf::Texture& texture, const sf::Texture& bulletTexture); + + void shoot() override; + void move(float deltaX, float deltaY) override; + void moveLeft() override; + void moveRight() override; + void moveUp() override; + void moveDown() override; + + void update(); + + bool isAlive() const; + void takeDamage(); + void updateDirection(); + +private: + sf::Clock shootClock; + sf::Texture enemyBulletTexture; + float movementSpeed = 2.0f; + bool alive = true; + DirectionA direction = DirectionA::Down; +}; +#endif // ADVANCED_ENEMY_H diff --git a/headers/Beam.h b/headers/Beam.h new file mode 100644 index 0000000..704d15d --- /dev/null +++ b/headers/Beam.h @@ -0,0 +1,29 @@ +#ifndef LOTOSTATEK_BEAM_H +#define LOTOSTATEK_BEAM_H + +#include +#include "Position.h" + +class Beam { +public: + Beam(float x, float y, float width, float height, const sf::Color& color); + + void draw(sf::RenderWindow &window); + + void update(); + void render(sf::RenderWindow& window); + + sf::FloatRect getBounds() const; + + bool isVisible() const; + void setVisible(bool visible); + + +private: + sf::RectangleShape beamShape; + bool visible; + sf::Texture beamTexture; + sf::Sprite beamSprite; +}; + +#endif // LOTOSTATEK_BEAM_H \ No newline at end of file diff --git a/headers/Bomber.h b/headers/Bomber.h new file mode 100644 index 0000000..562268d --- /dev/null +++ b/headers/Bomber.h @@ -0,0 +1,45 @@ +// +// Created by k on 11.12.2024. +// + +#ifndef BOMBER_H +#define BOMBER_H + +#include "Enemy.h" +#include "Actor.h" +enum class DirectionB { + Up, + Down, + Left, + Right +}; + +class Bomber : public Actor { +public: + Bomber(int x, int y, const sf::Texture& texture, const sf::Texture& bulletTexture); + + void shoot() override; + void move(float deltaX, float deltaY) override; + void moveLeft() override; + void moveRight() override; + void moveUp() override; + void moveDown() override; + void setRandomDirection(); + + void update(); + + bool isAlive() const; + void takeDamage(); + void updateDirection(); + void setPlanszaHeight(float height, float width); + +private: + float planszaHeight = 800.f; + float planszaWidth = 600.f; + sf::Clock shootClock; + sf::Texture BombaTexture; + float movementSpeed = 2.0f; + bool alive = true; + DirectionB direction = DirectionB::Down; +}; +#endif //BOMBER_H diff --git a/headers/Bullet.h b/headers/Bullet.h index d6bc301..cc29809 100644 --- a/headers/Bullet.h +++ b/headers/Bullet.h @@ -8,6 +8,8 @@ class Bullet : public Projectile { public: Bullet(float x, float y, sf::Texture &texture) : Projectile(x,y, texture) {}; void update() override; +private: + float directionY; }; diff --git a/headers/Enemy.h b/headers/Enemy.h new file mode 100644 index 0000000..bb7c81f --- /dev/null +++ b/headers/Enemy.h @@ -0,0 +1,39 @@ +#ifndef ENEMY_H +#define ENEMY_H + +#include "Actor.h" +#include "SFML/System/Clock.hpp" + +enum class Direction { + Up, + Down, + Left, + Right +}; + +class Enemy : public Actor { +public: + Enemy(int x, int y, const sf::Texture& texture) ; + + void shoot() override; + void move(float deltaX, float deltaY) override; + void moveLeft() override; + void moveRight() override; + void moveUp() override; + void moveDown() override; + + void update(); + + bool isAlive() const; + void takeDamage(); + void updateDirection(); + +private: + sf::Clock shootClock; + sf::Texture enemyBulletTexture; + float movementSpeed = 2.0f; + bool alive = true; + Direction direction = Direction::Down; +}; + +#endif // ENEMY_H diff --git a/headers/Kamikadze.h b/headers/Kamikadze.h new file mode 100644 index 0000000..9445530 --- /dev/null +++ b/headers/Kamikadze.h @@ -0,0 +1,46 @@ +#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; + bool isExploding() const; + void takeDamage(); + void updateDirection(); + + void followPlayer(const sf::Vector2f &playerPosition); + + void explode(const sf::Vector2f &playerPosition, bool &playerHit); + +private: + bool exploding = false; + 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 ed5ce85..96f7f3d 100644 --- a/headers/Plansza.h +++ b/headers/Plansza.h @@ -1,27 +1,37 @@ #ifndef PLANSZA_H #define PLANSZA_H -#include "Meteor.h" -#include "RandomNumberGenerator.h" #include "SFML/System/Clock.hpp" #include "SFML/Graphics/RenderWindow.hpp" -#include "Size.h" +#include "Meteor.h" +#include "Enemy.h" +#include "AdvancedEnemy.h" +#include "Bomber.h" +#include "Kamikadze.h" +#include "Wiazkowiec.h" #include "Player.h" #include "Background.h" #include "AudioManager.h" -#include "Meteor.h" #include "Plansza.h" +#include "Size.h" class Plansza { public: - Plansza(unsigned int windowHeight,unsigned int windowWidth, sf::RenderWindow *mainWindow); + Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::RenderWindow *mainWindow, + const sf::Texture& playerTexture, const sf::Texture& playerBulletTexture, const sf::Texture& playerRocketTexture); Size getSize(); std::vector &getMeteors(); void spawn_meteor(); void update_meteors(); void update(); void update_score(); + void spawn_enemy(); + void setOutOfBounds(bool status); + void spawn_advanced_enemy(); + void spawn_wiazkowiec(); + void spawn_bomber(); + void spawn_kamikadze(); private: Size size; Background background; @@ -29,8 +39,30 @@ private: AudioManager audioManager; sf::Texture meteorTexture1; sf::Texture meteorTexture2; + sf::Texture enemyBulletTexture; + sf::Texture WiazkaTexture; + sf::Texture BombaTexture; + sf::Texture playerTexture; + sf::Texture playerBulletTexture; + sf::Texture playerRocketTexture; + sf::Texture enemyTexture; + sf::Texture advancedEnemyTexture; + sf::Texture BomberEnemyTexture; + sf::Texture KamikadzeTexture; + sf::Texture WiazkowiecTexture; sf::Clock spawnClock; sf::Clock scoreClock; + sf::Clock shooterSpawnClock; + std::vector enemies; + std::vector AEnemies; + std::vector BEnemies; + std::vector KEnemies; + std::vector WEnemies; + sf::Clock enemySpawnClock; + sf::Clock AenemySpawnClock; + sf::Clock BomberSpawnClock; + sf::Clock KamikadzeSpawnClock; + sf::Clock WiazkowiecSpawnClock; std::vector meteors; sf::RenderWindow *window; sf::Font font; diff --git a/headers/Player.h b/headers/Player.h index e6b4c01..a3a64d6 100644 --- a/headers/Player.h +++ b/headers/Player.h @@ -3,12 +3,15 @@ #include +#include + #include "Actor.h" #include "Rocket.h" class Player : public Actor { public: - Player(int x, int y, std::string path); + Player(int x, int y, const sf::Texture& texture, const sf::Texture& bulletTexture, const sf::Texture& rocketTexture); + void setTextures(const sf::Texture& shipTexture, const sf::Texture& bulletTexture, const sf::Texture& rocketTexture); void shoot() override; void alternate_shoot(); void setFirerate(unsigned int firerate); @@ -17,12 +20,19 @@ public: void moveRight() override; void moveUp() override; void moveDown() override; + void takeDamage(); + bool isAlive() const; + void update(); std::vector& getRockets(); private: std::chrono::steady_clock::time_point lastShotTime = std::chrono::steady_clock::now(); std::vector rockets; sf::Texture rocketTexture; + int health = 3; // Liczba punktów życia gracza sf::Texture bulletTexture; + bool isImmortal = false; // flaga na immortal + sf::Clock immortalityClock; // Zegar kontrolujący czas nieśmiertelności + float immortalityDuration = 1.5f; // Czas trwania nieśmiertelności w sec }; diff --git a/headers/Rocket.h b/headers/Rocket.h index 37503f7..1707559 100644 --- a/headers/Rocket.h +++ b/headers/Rocket.h @@ -7,6 +7,7 @@ class Rocket : public Projectile{ public: Rocket(float x, float y, sf::Texture &texture) : Projectile(x,y, texture) {}; void update() override; + }; diff --git a/headers/Wiazkowiec.h b/headers/Wiazkowiec.h new file mode 100644 index 0000000..cf996ad --- /dev/null +++ b/headers/Wiazkowiec.h @@ -0,0 +1,54 @@ +#ifndef WIAZKOWIEC_H +#define WIAZKOWIEC_H + +#include "Enemy.h" +#include "Actor.h" +#include "Beam.h" +enum class DirectionW { + Up, + Down, + Left, + Right +}; + +class Wiazkowiec : public Actor { +public: + Wiazkowiec(int x, int y, const sf::Texture& texture); + + void shoot() override; + void move(float deltaX, float deltaY) override; + void moveLeft() override; + void moveRight() override; + void moveUp() override; + void moveDown() override; + void setRandomDirection(); + + void update(); + + void render(sf::RenderWindow &window); + + bool isAlive() const; + void takeDamage(); + void updateDirection(); + bool isShooting() const; + const Beam& getBeam() const; + void setPlanszaHeight(float height, float width); + void setMapBounds(float width, float height); + + +private: + float planszaHeight = 800.f; + float planszaWidth = 600.f; + sf::Clock shootClock; + sf::Texture WiazkaTexture; + float movementSpeed = 2.0f; + bool alive = true; + DirectionW direction = DirectionW::Down; + Beam beam; // Wiązka + bool shooting = false; + sf::Clock shootingClock; + float beamDuration = 1.0f; + void spawnBeam(); // Tworzy wiązkę +}; + +#endif //WIAZKOWIEC_H diff --git a/main.cpp b/main.cpp index a794292..6c612bc 100644 --- a/main.cpp +++ b/main.cpp @@ -6,6 +6,13 @@ int main() { std::clog << "Game started\n"; + sf::Texture playerTexture, playerBulletTexture, playerRocketTexture; + if (!playerTexture.loadFromFile("../assets/ship/Dreadnought-Base.png") || + !playerBulletTexture.loadFromFile("../assets/img/bullets/bullet_pink.png") || + !playerRocketTexture.loadFromFile("../assets/img/rockets/Rocket_111.png")) { + std::cerr << "Failed to load player textures!" << std::endl; + return -1; + } sf::RenderWindow mainWindow(sf::VideoMode(600, 800), "LotoStatek"); mainWindow.setVerticalSyncEnabled(true); mainWindow.setFramerateLimit(60); @@ -14,7 +21,9 @@ int main() icon.loadFromFile("../assets/img/icon/ikonka.png"); mainWindow.setIcon(128, 128, icon.getPixelsPtr()); - Plansza plansza(mainWindow.getSize().y, mainWindow.getSize().x, &mainWindow); + + + Plansza plansza(mainWindow.getSize().y, mainWindow.getSize().x, &mainWindow,playerTexture, playerBulletTexture, playerRocketTexture); while (mainWindow.isOpen()) { mainWindow.clear(); diff --git a/sources/Actor.cpp b/sources/Actor.cpp index 2170a24..5770cbd 100644 --- a/sources/Actor.cpp +++ b/sources/Actor.cpp @@ -1,7 +1,9 @@ #include "../headers/Actor.h" -Actor::Actor(int x, int y, std::string path) { - loadTexture(path); +#include + +Actor::Actor(int x, int y, const sf::Texture& texture) { + actorSprite.setTexture(texture); position.x = x; position.y = y; actorSprite.setOrigin(actorSprite.getLocalBounds().width / 2, actorSprite.getLocalBounds().height / 2); // wycentrowanie sprite @@ -17,6 +19,9 @@ void Actor::loadTexture(std::string path) { } sf::Sprite &Actor::getSprite() { + if (!actorSprite.getTexture()) { + std::cerr << "actorSprite has no texture set!" << std::endl; + } return actorSprite; } @@ -29,13 +34,17 @@ std::vector &Actor::getBullets() { } void Actor::updateBullets() { - for (auto& bullet : bullets) { - if(bullet.isOutOfBounds()) { - bullets.erase(bullets.begin()); + for (auto it = bullets.begin(); it != bullets.end(); ) { + if (it->isOutOfBounds()) { + it = bullets.erase(it); // Usuwa element i zwraca iterator na następny element + } else { + ++it; // Przechodzi do następnego elementu } } + //std::cout << "Liczba pociskow: " << bullets.size() << std::endl; } + void Actor::setMovingSpeed(float speed) { moving_speed = speed; } diff --git a/sources/AdvancedEnemy.cpp b/sources/AdvancedEnemy.cpp new file mode 100644 index 0000000..44be9ee --- /dev/null +++ b/sources/AdvancedEnemy.cpp @@ -0,0 +1,89 @@ +#include "../headers/AdvancedEnemy.h" +#include "../headers/Bullet.h" + +AdvancedEnemy::AdvancedEnemy(int x, int y, const sf::Texture& texture, const sf::Texture& bulletTexture) : Actor(x, y, texture) { + actorSprite.setTexture(texture); + enemyBulletTexture = bulletTexture; + hp = 2; // 2 punkty życia + firerate = 2000; // Strzela co 2 + moving_speed = 2.0f; // Prędkość + enemyBulletTexture.loadFromFile("../assets/img/bullets/enemy_bullet.png"); +} + +void AdvancedEnemy::shoot() { + if (shootClock.getElapsedTime().asMilliseconds() >= firerate) { + Bullet Cbullet(position.x, position.y + actorSprite.getGlobalBounds().height / 2, enemyBulletTexture); + Cbullet.setSpeed(10.0f); // Prędkość w dół + bullets.emplace_back(std::move(Cbullet)); + + Bullet Lbullet(position.x - 20, position.y + actorSprite.getGlobalBounds().height / 2, enemyBulletTexture); + Lbullet.setSpeed(10.0f); // Prędkość w dół + bullets.emplace_back(std::move(Lbullet)); + + Bullet Rbullet(position.x + 20, position.y + actorSprite.getGlobalBounds().height / 2, enemyBulletTexture); + Rbullet.setSpeed(10.0f); // Prędkość w dół + bullets.emplace_back(std::move(Rbullet)); + + shootClock.restart(); + } +} + +void AdvancedEnemy::updateDirection() { + // Zmieniamy kierunek przeciwnika, gdy dotrze do krawędzi + if (position.y <= 0) { + direction = DirectionA::Down; + } else if (position.y >= 800) { + direction = DirectionA::Up; + } + + // logika dla kierunku lewo/prawo + if (position.x <= 0) { + direction = DirectionA::Right; + } else if (position.x >= 1200) { + direction = DirectionA::Left; + } +} + +void AdvancedEnemy::move(float deltaX, float deltaY) { + actorSprite.move(deltaX, deltaY); + position.x += static_cast(deltaX); + position.y += static_cast(deltaY); +} + + + +void AdvancedEnemy::moveLeft() { move(-moving_speed, 0.0f); } +void AdvancedEnemy::moveRight() { move(moving_speed, 0.0f); } +void AdvancedEnemy::moveUp() { move(0.0f, -moving_speed); } +void AdvancedEnemy::moveDown() { move(0.0f, moving_speed); } + +void AdvancedEnemy::update() { + // Sprawdzamy, czy przeciwnik dotarł do krawędzi i zmieniamy kierunek + updateDirection(); + + switch (direction) { + case DirectionA::Up: + moveUp(); + break; + case DirectionA::Down: + moveDown(); + break; + case DirectionA::Left: + moveLeft(); + break; + case DirectionA::Right: + moveRight(); + break; + } +} + + +bool AdvancedEnemy::isAlive() const { + return alive; +} + +void AdvancedEnemy::takeDamage() { + if (--hp <= 0) { + alive = false; + } +} \ No newline at end of file diff --git a/sources/Beam.cpp b/sources/Beam.cpp new file mode 100644 index 0000000..c0771a6 --- /dev/null +++ b/sources/Beam.cpp @@ -0,0 +1,51 @@ +#include "../headers/Beam.h" + +#include + +Beam::Beam(float x, float y, float width, float height, const sf::Color& color) + : visible(false) { + beamShape.setPosition(x, y); + beamShape.setSize({width, height}); + beamShape.setFillColor(color); + + if (!beamTexture.loadFromFile("../assets/img/wiazka/wiazka.png")) { + std::cerr << "Błąd! Nie można załadować tekstury wiazka.png" << std::endl; + } + beamSprite.setTexture(beamTexture); + + if (beamTexture.getSize().x > 0 && beamTexture.getSize().y > 0) { + float scaleX = width / beamTexture.getSize().x; + float scaleY = height / beamTexture.getSize().y; + beamSprite.setScale(scaleX, scaleY); + beamSprite.setPosition(x, y); + } else { + std::cerr << "Błąd: Tekstura wiązki nie została poprawnie załadowana." << std::endl; + } + +} + +void Beam::draw(sf::RenderWindow& window) { + + window.draw(beamSprite); + +} + +void Beam::update() { +} + +void Beam::render(sf::RenderWindow& window) { + window.draw(beamSprite); +} + +sf::FloatRect Beam::getBounds() const { + return beamShape.getGlobalBounds(); +} + +bool Beam::isVisible() const { + return visible; +} + +void Beam::setVisible(bool visible) { + this->visible = visible; +} + diff --git a/sources/Bomber.cpp b/sources/Bomber.cpp new file mode 100644 index 0000000..7a81cd9 --- /dev/null +++ b/sources/Bomber.cpp @@ -0,0 +1,125 @@ +#include "../headers/Bomber.h" +#include "../headers/Bullet.h" +#include + +Bomber::Bomber(int x, int y, const sf::Texture& texture, const sf::Texture& bulletTexture) : Actor(x, y, texture) { + actorSprite.setTexture(texture); + BombaTexture = bulletTexture; + hp = 2; // 2 punkty życia + firerate = 10000; // Strzela co 10 + moving_speed = 10.0f; // Prędkość +} + +void Bomber::setPlanszaHeight(float height, float width) { + planszaHeight = height; + planszaWidth = width; +} + +void Bomber::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 = DirectionB::Up; + break; + case 1: + if (position.y < 600) direction = DirectionB::Down; + break; + case 2: + if (position.x > 0) direction = DirectionB::Left; + break; + case 3: + if (position.x < 800) direction = DirectionB::Right; + break; + } +} + +void Bomber::shoot() { + if (shootClock.getElapsedTime().asMilliseconds() >= firerate) { + Bullet Bbullet(position.x, position.y + actorSprite.getGlobalBounds().height / 2, BombaTexture); + Bbullet.setSpeed(0.1f); // Prędkość w dół + bullets.emplace_back(std::move(Bbullet)); + shootClock.restart(); + setRandomDirection(); + } +} + +void Bomber::updateDirection() { + auto spriteBounds = actorSprite.getGlobalBounds(); // Pobierz rozmiar i pozycję sprite'a + + // Kontrola górnej i dolnej krawędzi (wysokości planszy) + if (position.y <= 0) { + direction = DirectionB::Down; + } else if (position.y + spriteBounds.height >= planszaHeight) { + direction = DirectionB::Up; + } + + // Kontrola lewej i prawej krawędzi (szerokości planszy) + if (position.x <= 0) { + direction = DirectionB::Right; + } else if (position.x + spriteBounds.width >= planszaWidth) { + direction = DirectionB::Left; + } +} + +void Bomber::move(float deltaX, float deltaY) { + auto spriteBounds = actorSprite.getGlobalBounds(); // Rozmiar i pozycja sprite'a + + // Zapobiegaj wyjściu poza poziome granice + if (position.x + deltaX < 0) { + deltaX = -position.x; + } else if (position.x + spriteBounds.width + deltaX > planszaWidth) { + deltaX = planszaWidth - (position.x + spriteBounds.width); + } + + // Zapobiegaj wyjściu poza pionowe granice + if (position.y + deltaY < 0) { + deltaY = -position.y; + } else if (position.y + spriteBounds.height + deltaY > planszaHeight) { + deltaY = planszaHeight - (position.y + spriteBounds.height); + } + actorSprite.move(deltaX, deltaY); + position.x += static_cast(deltaX); + position.y += static_cast(deltaY); +} + +void Bomber::moveLeft() { move(-moving_speed, 0.0f); } +void Bomber::moveRight() { move(moving_speed, 0.0f); } +void Bomber::moveUp() { move(0.0f, -moving_speed); } +void Bomber::moveDown() { move(0.0f, moving_speed); } + +void Bomber::update() { + // Sprawdzamy, czy przeciwnik dotarł do krawędzi i zmieniamy kierunek + updateDirection(); + + switch (direction) { + case DirectionB::Up: + moveUp(); + break; + case DirectionB::Down: + moveDown(); + break; + case DirectionB::Left: + moveLeft(); + break; + case DirectionB::Right: + moveRight(); + break; + } +} + + +bool Bomber::isAlive() const { + return alive; +} + +void Bomber::takeDamage() { + if (--hp <= 0) { + alive = false; + } +} \ No newline at end of file diff --git a/sources/Bullet.cpp b/sources/Bullet.cpp index 17ff7a2..226401f 100644 --- a/sources/Bullet.cpp +++ b/sources/Bullet.cpp @@ -1,9 +1,13 @@ #include "../headers/Bullet.h" +#include +#include + void Bullet::update() { + //std::cout << "Start update: speed = " << speed << ", position.y = " << position.y << std::endl; sprite.move(0.0f, speed); position.y += int(speed); if(position.y < -100) { outOfBounds = true; } -} \ No newline at end of file +} diff --git a/sources/Enemy.cpp b/sources/Enemy.cpp new file mode 100644 index 0000000..9319e39 --- /dev/null +++ b/sources/Enemy.cpp @@ -0,0 +1,79 @@ +#include "../headers/Enemy.h" +#include "../headers/Bullet.h" + +Enemy::Enemy(int x, int y, const sf::Texture& texture) : Actor(x, y, texture) { + actorSprite.setTexture(texture); + hp = 1; // Przeciwnik ma 1 punkt życia + firerate = 2000; // Strzela co 2 + moving_speed = 2.0f; // Prędkość + enemyBulletTexture.loadFromFile("../assets/img/bullets/enemy_bullet.png"); +} + +void Enemy::shoot() { + if (shootClock.getElapsedTime().asMilliseconds() >= firerate) { + Bullet bullet(position.x, position.y + actorSprite.getGlobalBounds().height / 2, enemyBulletTexture); + bullet.setSpeed(10.0f); // Prędkość w dół + bullets.emplace_back(std::move(bullet)); + shootClock.restart(); + } +} + +void Enemy::updateDirection() { + // Zmieniamy kierunek przeciwnika, gdy dotrze do krawędzi + if (position.y <= 0) { + direction = Direction::Down; + } else if (position.y >= 800) { + direction = Direction::Up; + } + + // logika dla kierunku lewo/prawo + if (position.x <= 0) { + direction = Direction::Right; + } else if (position.x >= 1200) { + direction = Direction::Left; + } +} + +void Enemy::move(float deltaX, float deltaY) { + actorSprite.move(deltaX, deltaY); + position.x += static_cast(deltaX); + position.y += static_cast(deltaY); +} + + + +void Enemy::moveLeft() { move(-moving_speed, 0.0f); } +void Enemy::moveRight() { move(moving_speed, 0.0f); } +void Enemy::moveUp() { move(0.0f, -moving_speed); } +void Enemy::moveDown() { move(0.0f, moving_speed); } + +void Enemy::update() { + // Sprawdzamy, czy przeciwnik dotarł do krawędzi i zmieniamy kierunek + updateDirection(); + + switch (direction) { + case Direction::Up: + moveUp(); + break; + case Direction::Down: + moveDown(); + break; + case Direction::Left: + moveLeft(); + break; + case Direction::Right: + moveRight(); + break; + } +} + + +bool Enemy::isAlive() const { + return alive; +} + +void Enemy::takeDamage() { + if (--hp <= 0) { + alive = false; + } +} diff --git a/sources/Kamikadze.cpp b/sources/Kamikadze.cpp new file mode 100644 index 0000000..5067acd --- /dev/null +++ b/sources/Kamikadze.cpp @@ -0,0 +1,134 @@ +#include "../headers/Kamikadze.h" + +#include +#include + +#include "../headers/RandomNumberGenerator.h" + +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(){} + +void Kamikadze::setRandomDirection() { + int randomDirection = RandomNumberGenerator::getRandomNumber(0,3); + + // 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) { + float diffX = playerPosition.x - position.x; + float diffY = playerPosition.y - position.y; + + float magnitude = std::sqrt(diffX * diffX + diffY * diffY); + if (magnitude != 0) { + diffX /= magnitude; + diffY /= magnitude; + + // Aktualizacja pozycji Kamikadze w kierunku gracza + position.x += diffX * movementSpeed; + position.y += diffY * movementSpeed; + } else { //zatrzymanie kamikadze + movementSpeed = 0.0f; + } +} + +void Kamikadze::explode(const sf::Vector2f& playerPosition, bool& playerHit) { + if (!exploding) { + // Rozpocznij kamikadze + exploding = true; + explosionClock.restart(); + movementSpeed = 0.0f; + + std::cout << "Kamikadze exploding!" << std::endl; + std::cout << "Kamikadze position: (" << position.x << ", " << position.y << ")" << std::endl; + std::cout << "Player position: (" << playerPosition.x << ", " << playerPosition.y << ")" << std::endl; + + // Zakres, w jakim gracz może zostać trafiony + + 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); + + std::cout << "Distance to player: " << distance << std::endl; + + // Trafienie gracza, jeśli jest w obszarze eksplozji + const float explosionRange = 100.0f; + if (distance <= explosionRange) { + playerHit = true; + std::cout << "Player is within explosion range! Player hit!" << std::endl; + } + } + + // Sprawdzanie czasu wybuchu + if (exploding && explosionClock.getElapsedTime().asSeconds() >= 0.5f) { + alive = false; // Kamikadze ulega zniszczeniu po eksplozji + std::cout << "Kamikadze destroyed after explosion!" << std::endl; + } +} + +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ążanie za graczem, dopóki Kamikadze jest żywy + followPlayer(playerPosition); + actorSprite.setPosition(position.x, position.y); + } +} + +bool Kamikadze::isExploding() const { + return exploding; +} + +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 995ba12..918f1c1 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -3,11 +3,13 @@ #include "../headers/Plansza.h" #include "../headers/ObjectItem.hpp" -Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::RenderWindow *mainWindow) -: background("../assets/img/background/background.png", 2.0f), -ship(static_cast(mainWindow->getSize().x) / 2, static_cast(mainWindow->getSize().y) - 100, "../assets/ship/Dreadnought-Base.png") -{ - +Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::RenderWindow *mainWindow, + const sf::Texture& playerTexture, + const sf::Texture& playerBulletTexture, + const sf::Texture& playerRocketTexture) + : background("../assets/img/background/background.png", 2.0f), + ship(static_cast(mainWindow->getSize().x) / 2, static_cast(mainWindow->getSize().y) - 100, + playerTexture, playerBulletTexture, playerRocketTexture) { window = mainWindow; size.height = static_cast(windowHeight); size.width = static_cast(windowWidth); @@ -31,6 +33,32 @@ ship(static_cast(mainWindow->getSize().x) / 2, static_cast(mainWindow- meteorTexture1.loadFromFile("../assets/img/meteors/meteor-1.png"); meteorTexture2.loadFromFile("../assets/img/meteors/meteor-2.png"); + + // Ładowanie tekstur wrogów + if (!enemyTexture.loadFromFile("../assets/img/enemy/enemy.png")) { + std::cerr << "Failed to load enemy texture!" << std::endl; + exit(-1); + } + if (!advancedEnemyTexture.loadFromFile("../assets/img/enemy/advanced_enemy.png")) { + std::cerr << "Failed to load advanced enemy texture!" << std::endl; + exit(-1); + } + if (!BomberEnemyTexture.loadFromFile("../assets/img/enemy/bomber.png")) { + 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); + } + if (!WiazkowiecTexture.loadFromFile("../assets/img/enemy/wiazkowiec.png")) { + std::cerr << "Failed to load Wiazkowiec texture!" << std::endl; + exit(-1); + } spawnClock.restart(); } @@ -73,8 +101,14 @@ void Plansza::update() { } // generowanie nowego meteoru + ship.update(); + update_score(); spawn_meteor(); - + spawn_enemy(); + spawn_advanced_enemy(); + spawn_wiazkowiec(); + spawn_bomber(); + spawn_kamikadze(); // utrzymanie meteorów i pocisków w ruchu for (auto& meteor : getMeteors()) { @@ -131,6 +165,39 @@ void Plansza::update() { } } + + + if (!ship.isAlive()) { + std::cout << "Game Over! Player is dead." << std::endl; + std::cout << "You lost the game!\n"; + sf::RenderWindow errorWindow(sf::VideoMode(350, 200), "The end"); + sf::Font font; + if (!font.loadFromFile("../assets/fonts/arial.ttf")) { + std::cerr << "Error loading font\n"; + exit(-500); + } + sf::Text text("Your ship is destroyed!", font, 24); + text.setFillColor(sf::Color::Red); + text.setPosition(50, 80); + + // zatrzymanie muzyki i odtworzenie dźwięku przegranej + audioManager.playSoundEffect("fail", 70.f); + audioManager.stopBackgroundMusic(); + sf::Event event{}; + while (errorWindow.isOpen()) { + while (errorWindow.pollEvent(event)) { + if (event.type == sf::Event::Closed || sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) { + errorWindow.close(); + window->close(); + exit(-2); + } + } + errorWindow.clear(); + errorWindow.draw(text); + errorWindow.display(); + } + } + for (auto meteorIt = getMeteors().begin(); meteorIt != getMeteors().end(); ) { bool meteorHit = false; for (auto rocketIt = ship.getBullets().begin(); rocketIt != ship.getBullets().end(); ) { @@ -164,7 +231,412 @@ void Plansza::update() { ++meteorIt; } } - update_score(); + // Ruch i render przeciwnika + for (auto it = enemies.begin(); it != enemies.end();) { + it->update(); // Aktualizacja kierunku i ruchu + it->shoot(); + + window->draw(it->getSprite()); + + // Usunięcie martwych przeciwników + if (!it->isAlive()) { + std::cout << "Basic Enemy has been eliminated." << std::endl; + it = enemies.erase(it); + } else { + ++it; + } + } + for (auto it = AEnemies.begin(); it != AEnemies.end();) { + it->update(); // Ruch zaawansowanego przeciwnika + it->shoot(); // Strzał przeciwnika + + window->draw(it->getSprite()); // Rysowanie na ekranie + + if (!it->isAlive()) { + std::cout << "Advanced Enemy has been eliminated." << std::endl; + it = AEnemies.erase(it); // Usunięcie martwych przeciwników + } else { + ++it; + } + } + for (auto it = BEnemies.begin(); it != BEnemies.end();) { + it->update(); // Ruch bombera + it->shoot(); // Strzał przeciwnika + + window->draw(it->getSprite()); // Rysowanie na ekranie + + if (!it->isAlive()) { + std::cout << "Bomber has been eliminated." << std::endl; + it = BEnemies.erase(it); // Usunięcie martwych przeciwników + } else { + ++it; + } + } + + + for (auto it = KEnemies.begin(); it != KEnemies.end();) { + sf::Vector2f playerPosition = ship.getSprite().getPosition(); // Aktualna pozycja gracza + bool playerHit = false; + + it->update(playerPosition); + + // Wybuch, gdy Kamikadze dotknie gracza + if (ship.getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + it->explode(playerPosition, playerHit); + if (playerHit) { + ship.takeDamage(); // Gracz otrzymuje obrażenia + std::cout << "Gracz został trafiony przez eksplozję Kamikadze!" << std::endl; + } + } + + // Kamikadze eksploduje po aktywacji niezależnie od obecności gracza + if (it->isExploding()) { + it->explode(playerPosition, playerHit); // Eksplozja trwa + } + + // Usunięcie martwego Kamikadze + if (it->isAlive()) { + window->draw(it->getSprite()); + ++it; + } else { + std::cout << "Kamikadze 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();) { + if (ship.getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + ship.takeDamage(); // Zadanie obrażeń graczowi + it = aEnemy.getBullets().erase(it); // Usuwanie pocisku po trafieniu + } else { + ++it; + } + } + } + + // Obsługa bomb + for (auto& aEnemy : BEnemies) { + for (auto it = aEnemy.getBullets().begin(); it != aEnemy.getBullets().end();) { + if (ship.getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + ship.takeDamage(); // Zadanie obrażeń graczowi + it = aEnemy.getBullets().erase(it); // Usuwanie pocisku po trafieniu + } else { + ++it; + } + } + } + + + for (auto& enemy : enemies) { + enemy.shoot(); + enemy.updateBullets(); + for (auto& bullet : enemy.getBullets()) { + bullet.update(); + window->draw(bullet.getSprite()); + } + } + + for (auto& advancedEnemy : AEnemies) { + advancedEnemy.updateBullets(); // Obsługuje pociski zaawansowanych przeciwników + for (auto& bullet : advancedEnemy.getBullets()) { + bullet.update(); + window->draw(bullet.getSprite()); + } + } + + for (auto& bomberEnemy : BEnemies) { + bomberEnemy.updateBullets(); // Obsługuje bomby + for (auto& bullet : bomberEnemy.getBullets()) { + bullet.update(); + window->draw(bullet.getSprite()); + } + } + + for (auto& enemy : enemies) { + for (auto it = enemy.getBullets().begin(); it != enemy.getBullets().end();) { + if (ship.getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + // Kolizja wykryta + std::cout << "Player hit by enemy bullet!\n"; + + ship.takeDamage(); + + // Usuwanie pocisku + it = enemy.getBullets().erase(it); + } else { + ++it; // Brak kolizji, przechodzimy do kolejnego pocisku + } + } + } + + for (auto& bomberEnemy : BEnemies) { + for (auto it = bomberEnemy.getBullets().begin(); it != bomberEnemy.getBullets().end();) { + bool bulletDestroyed = false; + + // Kolizja pocisku gracza z pociskiem Bombera + for (auto playerBulletIt = ship.getBullets().begin(); playerBulletIt != ship.getBullets().end();) { + if (playerBulletIt->getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + // Usuń pocisk Bombera i pocisk gracza + it = bomberEnemy.getBullets().erase(it); + playerBulletIt = ship.getBullets().erase(playerBulletIt); + bulletDestroyed = true; + break; + } else { + ++playerBulletIt; + } + } + + // Kolizja rakiety gracza z pociskiem Bombera + if (!bulletDestroyed) { + for (auto rocketIt = ship.getRockets().begin(); rocketIt != ship.getRockets().end();) { + if (rocketIt->getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + // Usuń pocisk Bombera i rakietę gracza + it = bomberEnemy.getBullets().erase(it); + rocketIt = ship.getRockets().erase(rocketIt); + bulletDestroyed = true; + break; + } else { + ++rocketIt; + } + } + } + + // Jeśli pocisk Bombera przetrwał dotychczasowe sprawdzenia, wykonaj inne działania + if (!bulletDestroyed) { + if (ship.getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + // Kolizja pocisku Bombera z graczem + ship.takeDamage(); + it = bomberEnemy.getBullets().erase(it); + } else { + ++it; + } + } + } + } + + for (auto& wiazkowiec : WEnemies) { + wiazkowiec.update(); + + if (wiazkowiec.isShooting() && wiazkowiec.getBeam().isVisible()) { + if (ship.getSprite().getGlobalBounds().intersects(wiazkowiec.getBeam().getBounds())) { + ship.takeDamage(); // Gracz otrzymuje obrażenia + } + } + + window->draw(wiazkowiec.getSprite()); + wiazkowiec.render(*window); + } + + // Usuwanie pocisków, które są poza ekranem srednio to dziala + for (auto enemyIt = enemies.begin(); enemyIt != enemies.end(); ) { + for (auto bulletIt = enemyIt->getBullets().begin(); bulletIt != enemyIt->getBullets().end();) { + if (bulletIt->isOutOfBounds()) { + bulletIt = enemyIt->getBullets().erase(bulletIt); // Usuwamy pocisk, który wyszedł poza ekran + } else { + ++bulletIt; + } + } + ++enemyIt; + } + + + // Kolizje między pociskami gracza a przeciwnikami + for (auto enemyIt = enemies.begin(); enemyIt != enemies.end();) { + bool hit = false; + for (auto bulletIt = ship.getBullets().begin(); bulletIt != ship.getBullets().end();) { + if (enemyIt->getSprite().getGlobalBounds().intersects(bulletIt->getSprite().getGlobalBounds())) { + bulletIt = ship.getBullets().erase(bulletIt); + enemyIt->takeDamage(); + hit = true; + break; + } else { + ++bulletIt; + } + } + if (hit && !enemyIt->isAlive()) { + enemyIt = enemies.erase(enemyIt); + } else { + ++enemyIt; + } + } + + for (auto advancedIt = AEnemies.begin(); advancedIt != AEnemies.end();) { + bool hit = false; + for (auto bulletIt = ship.getBullets().begin(); bulletIt != ship.getBullets().end();) { + if (advancedIt->getSprite().getGlobalBounds().intersects(bulletIt->getSprite().getGlobalBounds())) { + bulletIt = ship.getBullets().erase(bulletIt); + advancedIt->takeDamage(); + hit = true; + break; + } else { + ++bulletIt; + } + } + if (hit && !advancedIt->isAlive()) { + advancedIt = AEnemies.erase(advancedIt); // Usunięcie przeciwnika AdvancedEnemy + } else { + ++advancedIt; + } + } + + for (auto bomberIt = BEnemies.begin(); bomberIt != BEnemies.end();) { + bool hit = false; + for (auto bulletIt = ship.getBullets().begin(); bulletIt != ship.getBullets().end();) { + if (bomberIt->getSprite().getGlobalBounds().intersects(bulletIt->getSprite().getGlobalBounds())) { + bulletIt = ship.getBullets().erase(bulletIt); + bomberIt->takeDamage(); + hit = true; + break; + } else { + ++bulletIt; + } + } + if (hit && !bomberIt->isAlive()) { + 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; + } + } + + for (auto wiazkowiecIt = WEnemies.begin(); wiazkowiecIt != WEnemies.end();) { + bool hit = false; + for (auto bulletIt = ship.getBullets().begin(); bulletIt != ship.getBullets().end();) { + if (wiazkowiecIt->getSprite().getGlobalBounds().intersects(bulletIt->getSprite().getGlobalBounds())) { + bulletIt = ship.getBullets().erase(bulletIt); + wiazkowiecIt->takeDamage(); + hit = true; + break; + } else { + ++bulletIt; + } + } + if (hit && !wiazkowiecIt->isAlive()) { + wiazkowiecIt = WEnemies.erase(wiazkowiecIt); // Usunięcie przeciwnika Wiazkowiec + } else { + ++wiazkowiecIt; + } + } + + + + //oblsuga dla rakiety + for (auto enemyIt = enemies.begin(); enemyIt != enemies.end();) { + bool hit = false; + for (auto rocketIt = ship.getRockets().begin(); rocketIt != ship.getRockets().end();) { + if (enemyIt->getSprite().getGlobalBounds().intersects(rocketIt->getSprite().getGlobalBounds())) { + rocketIt = ship.getRockets().erase(rocketIt); + enemyIt->takeDamage(); + hit = true; + break; + } else { + ++rocketIt; + } + } + if (hit && !enemyIt->isAlive()) { + enemyIt = enemies.erase(enemyIt); + } else { + ++enemyIt; + } + } + + for (auto advancedIt = AEnemies.begin(); advancedIt != AEnemies.end();) { + bool hit = false; + for (auto rocketIt = ship.getRockets().begin(); rocketIt != ship.getRockets().end();) { + if (advancedIt->getSprite().getGlobalBounds().intersects(rocketIt->getSprite().getGlobalBounds())) { + rocketIt = ship.getRockets().erase(rocketIt); + advancedIt->takeDamage(); + hit = true; + break; + } else { + ++rocketIt; + } + } + if (hit && !advancedIt->isAlive()) { + advancedIt = AEnemies.erase(advancedIt); + } else { + ++advancedIt; + } + } + + for (auto bomberIt = BEnemies.begin(); bomberIt != BEnemies.end();) { + bool hit = false; + for (auto rocketIt = ship.getRockets().begin(); rocketIt != ship.getRockets().end();) { + if (bomberIt->getSprite().getGlobalBounds().intersects(rocketIt->getSprite().getGlobalBounds())) { + rocketIt = ship.getRockets().erase(rocketIt); + bomberIt->takeDamage(); + hit = true; + break; + } else { + ++rocketIt; + } + } + if (hit && !bomberIt->isAlive()) { + bomberIt = BEnemies.erase(bomberIt); + } else { + ++bomberIt; + } + } + + 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; + } + } + + for (auto wiazkowiecIt = WEnemies.begin(); wiazkowiecIt != WEnemies.end();) { + bool hit = false; + for (auto rocketIt = ship.getRockets().begin(); rocketIt != ship.getRockets().end();) { + if (wiazkowiecIt->getSprite().getGlobalBounds().intersects(rocketIt->getSprite().getGlobalBounds())) { + rocketIt = ship.getRockets().erase(rocketIt); + wiazkowiecIt->takeDamage(); + hit = true; + break; + } else { + ++rocketIt; + } + } + if (hit && !wiazkowiecIt->isAlive()) { + wiazkowiecIt = WEnemies.erase(wiazkowiecIt); + } else { + ++wiazkowiecIt; + } + } + + } // Meteor-related niżej @@ -191,6 +663,59 @@ void Plansza::update_meteors() { } } +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(); + + } +} + +void Plansza::spawn_advanced_enemy() { + if (AenemySpawnClock.getElapsedTime().asSeconds() >= 80) { // Spawn co 10 sekund + int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); + AEnemies.emplace_back(spawnX, -50, advancedEnemyTexture, enemyBulletTexture); + std::cout << "Spawned Advanced Enemy at X: " << spawnX << std::endl; + AenemySpawnClock.restart(); + } +} + +void Plansza::spawn_bomber() { + if (BomberSpawnClock.getElapsedTime().asSeconds() >= 10) { // Spawn co 10 sekund + int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); + Bomber bomber(spawnX, -50, BomberEnemyTexture, BombaTexture); + bomber.setPlanszaHeight(size.height, size.width); // Przekazanie wysokości i szerokości okna + BEnemies.push_back(bomber); + std::cout << "Spawned Bomber Enemy at X: " << spawnX << std::endl; + BomberSpawnClock.restart(); + } +} + +void Plansza::spawn_kamikadze() { + if (KamikadzeSpawnClock.getElapsedTime().asSeconds() >= 220) { // 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(); + } +} + +void Plansza::spawn_wiazkowiec() { + if (WiazkowiecSpawnClock.getElapsedTime().asSeconds() >= 110) { // Spawn co 10 sekund + int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); + Wiazkowiec wiazkowiec(spawnX, -50, WiazkowiecTexture); + wiazkowiec.setPlanszaHeight(size.height, size.width); // Przekazanie wysokości i szerokosci okna + WEnemies.push_back(wiazkowiec); + std::cout << "Spawned Wiazkowiec Enemy at X: " << spawnX << std::endl; + WiazkowiecSpawnClock.restart(); + } +} + + + + Size Plansza::getSize() { return size; } diff --git a/sources/Player.cpp b/sources/Player.cpp index 91117cf..5e64758 100644 --- a/sources/Player.cpp +++ b/sources/Player.cpp @@ -1,11 +1,22 @@ #include "../headers/Player.h" + +#include +#include +#include +#include + #include "../headers/Bullet.h" -Player::Player(int x, int y, std::string path) : Actor(x, y, path) { - bulletTexture.loadFromFile("../assets/img/bullets/bullet_pink.png"); - rocketTexture.loadFromFile("../assets/img/rockets/Rocket_111.png"); +Player::Player(int x, int y, const sf::Texture& texture, const sf::Texture& bulletTexture, const sf::Texture& rocketTexture) : Actor(x, y, texture), bulletTexture(bulletTexture), rocketTexture(rocketTexture) { + }; +void Player::setTextures(const sf::Texture& shipTexture, const sf::Texture& bulletTexture, const sf::Texture& rocketTexture) { + this->actorSprite.setTexture(shipTexture); // Poprawiona nazwa - actorSprite zamiast shipSprite + this->bulletTexture = bulletTexture; + this->rocketTexture = rocketTexture; +} + void Player::shoot() { auto now = std::chrono::steady_clock::now(); if (std::chrono::duration_cast(now - lastShotTime).count() >= firerate) { @@ -14,6 +25,7 @@ void Player::shoot() { } } + void Player::alternate_shoot() { auto now = std::chrono::steady_clock::now(); if (std::chrono::duration_cast(now - lastShotTime).count() >= firerate) { @@ -22,6 +34,47 @@ void Player::alternate_shoot() { } } +void Player::update() { + // Wyłącz nieśmiertelność po określonym czasie + if (isImmortal && immortalityClock.getElapsedTime().asSeconds() >= immortalityDuration) { + isImmortal = false; + std::cout << "Immortality ended.\n"; + } + + // Efekt migania podczas nieśmiertelności + if (isImmortal) { + if (static_cast(immortalityClock.getElapsedTime().asMilliseconds() / 200) % 2 == 0) { + actorSprite.setColor(sf::Color(255, 255, 255, 128)); // Półprzezroczysty + } else { + actorSprite.setColor(sf::Color(255, 255, 255, 255)); // Normalny + } + } else { + actorSprite.setColor(sf::Color(255, 255, 255, 255)); // Normalny + } +} + +void Player::takeDamage() { + if (!isImmortal) { + if (health > 0) { + health--; + std::cout << "Player hit! Remaining health: " << health << "\n"; + isImmortal = true; // Aktywuj chwilową nieśmiertelność + immortalityClock.restart(); + + + if (health <= 0) { + std::cout << "Player has been destroyed!\n"; + std::cout << "You lost the game!\n"; + + } + } + } +} + +bool Player::isAlive() const { + return health > 0; +} + void Player::setFirerate(unsigned int firerate) { this->firerate = firerate; } diff --git a/sources/Rocket.cpp b/sources/Rocket.cpp index a5ae223..39af7af 100644 --- a/sources/Rocket.cpp +++ b/sources/Rocket.cpp @@ -6,4 +6,5 @@ void Rocket::update() { if(position.y < -100) { outOfBounds = true; } -} \ No newline at end of file +} + diff --git a/sources/Wiazkowiec.cpp b/sources/Wiazkowiec.cpp new file mode 100644 index 0000000..c51371b --- /dev/null +++ b/sources/Wiazkowiec.cpp @@ -0,0 +1,188 @@ +#include "../headers/Wiazkowiec.h" + +#include + +#include "../headers/Bullet.h" +#include + +Wiazkowiec::Wiazkowiec(int x, int y, const sf::Texture& texture) : Actor(x, y, texture), beam(0, 0, 50.f, 50.f, sf::Color::Red) { + actorSprite.setTexture(texture); + hp = 2; // 2 punkty życia + firerate = 5000; // Strzela co 10 + moving_speed = 5.0f; // Prędkość +} + +void Wiazkowiec::setPlanszaHeight(float height, float width) { + planszaHeight = height; + planszaWidth = width; +} + +void Wiazkowiec::spawnBeam() { + float beamX = position.x; + float beamY = position.y; + float beamWidth = 50.f; + float beamHeight = 0.f; + + switch (direction) { + case DirectionW::Up: + beamHeight = position.y; + beamY -= beamHeight; + beam = Beam(beamX, beamY, beamWidth, beamHeight, sf::Color::Red); + break; + case DirectionW::Down: + beamHeight = planszaHeight - position.y; + beam = Beam(beamX, beamY, beamWidth, beamHeight, sf::Color::Red); + break; + case DirectionW::Left: + beamHeight = 50.f; + beamWidth = position.x; + beamX -= beamWidth; + beamY = position.y + (actorSprite.getGlobalBounds().height / 2) - 25.f; + beam = Beam(beamX, beamY, beamWidth, beamHeight, sf::Color::Red); + break; + case DirectionW::Right: + beamHeight = 50.f; + beamWidth = 800 - position.x; + beamY = position.y + (actorSprite.getGlobalBounds().height / 2) - 25.f; + beam = Beam(beamX, beamY, beamWidth, beamHeight, sf::Color::Red); + break; + } + + beam = Beam(beamX, beamY, beamWidth, beamHeight, sf::Color::Red); + beam.setVisible(true); + + shooting = true; + shootingClock.restart(); +} + +// Strzał wiązki +void Wiazkowiec::shoot() { + if (!shooting) { + spawnBeam(); + std::cout << "Wiazkowiec shot a beam!" << std::endl; + } +} + +void Wiazkowiec::setRandomDirection() { + // Losowanie kierunku: 0 = Up, 1 = Down, 2 = Left, 3 = Right + int directionIndex = std::rand() % 4; + + switch (directionIndex) { + case 0: + direction = DirectionW::Up; + break; + case 1: + direction = DirectionW::Down; + break; + case 2: + direction = DirectionW::Left; + break; + case 3: + direction = DirectionW::Right; + break; + } +} + +void Wiazkowiec::updateDirection() { + auto spriteBounds = actorSprite.getGlobalBounds(); // Pobierz rozmiar i pozycję sprite'a + + // Kontrola górnej i dolnej krawędzi + if (position.y <= 0) { + direction = DirectionW::Down; + } else if (position.y + spriteBounds.height >= planszaHeight) { + direction = DirectionW::Up; + } + + // Kontrola lewej i prawej krawędzi + if (position.x <= 0) { + direction = DirectionW::Right; + } else if (position.x + spriteBounds.width >= planszaWidth) { + direction = DirectionW::Left; + } +} + + +void Wiazkowiec::move(float deltaX, float deltaY) { + auto spriteBounds = actorSprite.getGlobalBounds(); // Rozmiar i pozycja sprite'a + + // Zapobiegaj wyjściu poza poziome granice + if (position.x + deltaX < 0) { + deltaX = -position.x; + } else if (position.x + spriteBounds.width + deltaX > planszaWidth) { + deltaX = planszaWidth - (position.x + spriteBounds.width); + } + + // Zapobiegaj wyjściu poza pionowe granice + if (position.y + deltaY < 0) { + deltaY = -position.y; + } else if (position.y + spriteBounds.height + deltaY > planszaHeight) { + deltaY = planszaHeight - (position.y + spriteBounds.height); + } + + actorSprite.move(deltaX, deltaY); + position.x += static_cast(deltaX); + position.y += static_cast(deltaY); +} + +void Wiazkowiec::moveLeft() { move(-moving_speed, 0.0f); } +void Wiazkowiec::moveRight() { move(moving_speed, 0.0f); } +void Wiazkowiec::moveUp() { move(0.0f, -moving_speed); } +void Wiazkowiec::moveDown() { move(0.0f, moving_speed); } + +void Wiazkowiec::update() { + if (shooting) { + // Kontrola zakończenia strzału + if (shootingClock.getElapsedTime().asSeconds() >= beamDuration) { + beam.setVisible(false); + shooting = false; + setRandomDirection(); // Zmień kierunek po strzale + } + } else { + updateDirection(); + + switch (direction) { + case DirectionW::Up: + moveUp(); + break; + case DirectionW::Down: + moveDown(); + break; + case DirectionW::Left: + moveLeft(); + break; + case DirectionW::Right: + moveRight(); + break; + } + + if (shootClock.getElapsedTime().asSeconds() >= 3.0f) { // Co 3 sekundy + shoot(); + shootClock.restart(); + } + } +} + +// Ustawianie widoczności wiązki podczas renderowania +void Wiazkowiec::render(sf::RenderWindow& window) { + if (beam.isVisible()) { + beam.render(window); + } +} + +bool Wiazkowiec::isAlive() const { + return alive; +} + +void Wiazkowiec::takeDamage() { + if (--hp <= 0) { + alive = false; + } +} + +bool Wiazkowiec::isShooting() const { + return shooting; +} + +const Beam& Wiazkowiec::getBeam() const { + return beam; +} \ No newline at end of file