diff --git a/CMakeLists.txt b/CMakeLists.txt index d09862e..c301c75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,8 @@ add_executable(LotoStatek main.cpp sources/ObjectItem.cpp sources/Enemy.cpp headers/Enemy.h + headers/AdvancedEnemy.h + sources/AdvancedEnemy.cpp ) if(WIN32) 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..09fe88f --- /dev/null +++ b/headers/AdvancedEnemy.h @@ -0,0 +1,38 @@ +#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/Enemy.h b/headers/Enemy.h index 4af000d..bb7c81f 100644 --- a/headers/Enemy.h +++ b/headers/Enemy.h @@ -13,7 +13,7 @@ enum class Direction { class Enemy : public Actor { public: - Enemy(int x, int y, std::string path); + Enemy(int x, int y, const sf::Texture& texture) ; void shoot() override; void move(float deltaX, float deltaY) override; diff --git a/headers/Plansza.h b/headers/Plansza.h index 1fb9d2a..4173def 100644 --- a/headers/Plansza.h +++ b/headers/Plansza.h @@ -3,10 +3,12 @@ #include "Meteor.h" #include "Enemy.h" +#include "AdvancedEnemy.h" #include "RandomNumberGenerator.h" #include "SFML/System/Clock.hpp" #include "SFML/Graphics/RenderWindow.hpp" #include "Size.h" +#include #include "Player.h" #include "Background.h" @@ -16,7 +18,8 @@ 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(); @@ -26,6 +29,9 @@ public: void update(); void spawn_enemy(); void setOutOfBounds(bool status); + + void spawn_advanced_enemy(); + private: Size size; Background background; @@ -33,10 +39,18 @@ private: AudioManager audioManager; sf::Texture meteorTexture1; sf::Texture meteorTexture2; + sf::Texture enemyBulletTexture; + sf::Texture playerTexture; + sf::Texture playerBulletTexture; + sf::Texture playerRocketTexture; + sf::Texture enemyTexture; + sf::Texture advancedEnemyTexture; sf::Clock spawnClock; sf::Clock shooterSpawnClock; std::vector enemies; + std::vector AEnemies; sf::Clock enemySpawnClock; + sf::Clock AenemySpawnClock; std::vector meteors; sf::RenderWindow *window; }; diff --git a/headers/Player.h b/headers/Player.h index b4e0fd3..721d761 100644 --- a/headers/Player.h +++ b/headers/Player.h @@ -8,7 +8,8 @@ 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); 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 cff3f5d..5770cbd 100644 --- a/sources/Actor.cpp +++ b/sources/Actor.cpp @@ -2,8 +2,8 @@ #include -Actor::Actor(int x, int y, std::string path) { - loadTexture(path); +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 @@ -19,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; } 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/Enemy.cpp b/sources/Enemy.cpp index 0aca9ab..9319e39 100644 --- a/sources/Enemy.cpp +++ b/sources/Enemy.cpp @@ -1,7 +1,8 @@ #include "../headers/Enemy.h" #include "../headers/Bullet.h" -Enemy::Enemy(int x, int y, std::string path) : Actor(x, y, path) { +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ść diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 18dd01b..19727cb 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -3,15 +3,20 @@ #include "../headers/Plansza.h" #include "../headers/ObjectItem.hpp" -Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::RenderWindow *mainWindow) +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, "../assets/ship/Dreadnought-Base.png") +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); + + ship.setMovingSpeed(8); ship.setFirerate(200); @@ -23,8 +28,19 @@ ship(static_cast(mainWindow->getSize().x) / 2, static_cast(mainWindow- audioManager.loadSoundEffect("fail", "../assets/sounds/fail.mp3"); + 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); + } spawnClock.restart(); } @@ -69,6 +85,7 @@ void Plansza::update() { // generowanie nowego meteoru spawn_meteor(); spawn_enemy(); + spawn_advanced_enemy(); // utrzymanie meteorów i pocisków w ruchu for (auto& meteor : getMeteors()) { @@ -204,6 +221,58 @@ void Plansza::update() { ++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; + } + } + // std::cout << "Current AEnemies size: " << AEnemies.size() << std::endl; + // 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; + } + } + } + + 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& advancedEnemy : AEnemies) { + advancedEnemy.updateBullets(); // Obsługuje pociski zaawansowanych przeciwników + for (auto& bullet : advancedEnemy.getBullets()) { + bullet.update(); + window->draw(bullet.getSprite()); + } + } for (auto& enemy : enemies) { for (auto it = enemy.getBullets().begin(); it != enemy.getBullets().end();) { @@ -282,6 +351,26 @@ void Plansza::update() { } } + 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; + } + } + + } // Meteor-related niżej @@ -309,14 +398,26 @@ void Plansza::update_meteors() { } void Plansza::spawn_enemy() { - if (enemySpawnClock.getElapsedTime().asSeconds() >= 10) { // Spawn co 10 sekund + if (enemySpawnClock.getElapsedTime().asSeconds() >= 6) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); - enemies.emplace_back(spawnX, -50, "../assets/img/enemy/enemy.png"); + enemies.emplace_back(spawnX, -50, enemyTexture); + enemySpawnClock.restart(); } } +void Plansza::spawn_advanced_enemy() { + if (AenemySpawnClock.getElapsedTime().asSeconds() >= 5) { // 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(); + } +} + + + Size Plansza::getSize() { return size; } diff --git a/sources/Player.cpp b/sources/Player.cpp index e5315b0..f3b3810 100644 --- a/sources/Player.cpp +++ b/sources/Player.cpp @@ -7,11 +7,16 @@ #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) { @@ -20,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) {