diff --git a/CMakeLists.txt b/CMakeLists.txt index f59d699..7100bf9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,10 @@ add_executable(LotoStatek main.cpp sources/Background.cpp headers/AudioManager.h sources/AudioManager.cpp -) + sources/Bullet.cpp + headers/Meteor.h + sources/Meteor.cpp + headers/RandomNumberGenerator.h) if(WIN32) set(SFML_ROOT "${CMAKE_SOURCE_DIR}/SFML") diff --git a/assets/fonts/arial.TTF b/assets/fonts/arial.TTF new file mode 100644 index 0000000..8682d94 Binary files /dev/null and b/assets/fonts/arial.TTF differ diff --git a/assets/img/Rocket_111.png b/assets/img/Rocket_111.png new file mode 100644 index 0000000..fa76649 Binary files /dev/null and b/assets/img/Rocket_111.png differ diff --git a/assets/img/Rocket_115.png b/assets/img/Rocket_115.png new file mode 100644 index 0000000..bf18330 Binary files /dev/null and b/assets/img/Rocket_115.png differ diff --git a/assets/img/meteor-1.png b/assets/img/meteor-1.png new file mode 100644 index 0000000..5c829ec Binary files /dev/null and b/assets/img/meteor-1.png differ diff --git a/assets/img/meteor-2.png b/assets/img/meteor-2.png new file mode 100644 index 0000000..79a561b Binary files /dev/null and b/assets/img/meteor-2.png differ diff --git a/assets/ship/Dreadnought-Base.png b/assets/ship/Dreadnought-Base.png index 70cbf76..3944b15 100644 Binary files a/assets/ship/Dreadnought-Base.png and b/assets/ship/Dreadnought-Base.png differ diff --git a/headers/Actor.h b/headers/Actor.h index 70319be..56b704a 100644 --- a/headers/Actor.h +++ b/headers/Actor.h @@ -31,9 +31,7 @@ public: void updateBullets(); - void setMovingSpeed(float speed) { - moving_speed = speed; - } + void setMovingSpeed(float speed); protected: sf::Sprite actorSprite; diff --git a/headers/Bullet.h b/headers/Bullet.h index e4c34d4..74d2539 100644 --- a/headers/Bullet.h +++ b/headers/Bullet.h @@ -11,16 +11,16 @@ class Bullet { }; public: - Bullet(float x, float y, sf::Texture &bulletTexture); - void update(); - sf::Sprite& getSprite(); + Bullet(float x, float y, sf::Texture &texture); + sf::Sprite &getSprite(); void setSpeed(float speed); bool getStatus() const; + void update(); private: sf::Sprite bulletSprite; sf::Texture bulletTexture; - float bulletSpeed; Position bulletPosition; + float bulletSpeed; bool outOfBounds; }; diff --git a/headers/Meteor.h b/headers/Meteor.h new file mode 100644 index 0000000..8b42356 --- /dev/null +++ b/headers/Meteor.h @@ -0,0 +1,30 @@ +#ifndef LOTOSTATEK_METEOR_H +#define LOTOSTATEK_METEOR_H + +#include "SFML/Graphics/Texture.hpp" +#include "SFML/Graphics/Sprite.hpp" + +class Meteor { + struct Position { + int x; + int y; + }; + +public: + Meteor(float x, float y, sf::Texture &texture); + sf::Sprite &getSprite(); + bool getStatus(); + void update(); +// ~Meteor(); +private: + sf::Texture meteorTexture; + sf::Sprite meteorSprite; + Position meteorPosition; + float meteorRotationSpeed; + float meteorSpeed; + bool outOfBounds; + static unsigned int counter; +}; + + +#endif //LOTOSTATEK_METEOR_H diff --git a/headers/Plansza.h b/headers/Plansza.h index eab0b3e..3aae063 100644 --- a/headers/Plansza.h +++ b/headers/Plansza.h @@ -2,11 +2,27 @@ #define PLANSZA_H +#include "Meteor.h" +#include "RandomNumberGenerator.h" +#include "SFML/System/Clock.hpp" class Plansza { - + struct Size { + int height; + int width; + }; +public: + Plansza(unsigned int windowHeight, unsigned int windowWidth); + void spawn_meteor(); + Size getSize(); + std::vector &getMeteors(); + void update_meteors(); +private: + std::vector meteors; + Size size; + sf::Texture meteorTexture1; + sf::Texture meteorTexture2; + sf::Clock spawnClock; }; - - #endif //PLANSZA_H diff --git a/headers/RandomNumberGenerator.h b/headers/RandomNumberGenerator.h new file mode 100644 index 0000000..49b3acb --- /dev/null +++ b/headers/RandomNumberGenerator.h @@ -0,0 +1,16 @@ +#ifndef LOTOSTATEK_RANDOMNUMBERGENERATOR_H +#define LOTOSTATEK_RANDOMNUMBERGENERATOR_H + +#include + +class RandomNumberGenerator { +public: + static int getRandomNumber(int min, int max) { + static std::random_device rd; + static std::mt19937 gen(rd()); + static std::uniform_int_distribution<> dis(min, max); + return dis(gen); + } +}; + +#endif //LOTOSTATEK_RANDOMNUMBERGENERATOR_H diff --git a/main.cpp b/main.cpp index efac1e1..4763518 100644 --- a/main.cpp +++ b/main.cpp @@ -1,18 +1,20 @@ #include -#include #include "SFML/Graphics.hpp" #include "headers/Player.h" #include "headers/Bullet.h" #include "headers/Background.h" #include "headers/AudioManager.h" +#include "headers/Meteor.h" +#include "headers/Plansza.h" int main() { std::clog << "Game started\n"; - sf::RenderWindow window(sf::VideoMode(600, 800), "My window"); - window.setVerticalSyncEnabled(true); - window.setFramerateLimit(60); + sf::RenderWindow mainWindow(sf::VideoMode(600, 800), "My mainWindow"); + mainWindow.setVerticalSyncEnabled(true); + mainWindow.setFramerateLimit(60); + Plansza plansza(mainWindow.getSize().y, mainWindow.getSize().x); Background background("../assets/img/space.png", 2.0f); //tutaj predkosc tla, mozna zwiekszyc jak za wolno @@ -27,20 +29,22 @@ int main() audioManager.loadSoundEffect("shoot_alt", "../assets/sounds/shoot_alt.ogg"); - Player ship(240,650, "../assets/ship/Dreadnought-Base.png"); // tworzenie statku + // TODO: Przenieść tworzenie statku wewnątrz klasy Plansza + Player ship(mainWindow.getSize().x / 2, mainWindow.getSize().y - 100, "../assets/ship/Dreadnought-Base.png"); // tworzenie statku ship.setMovingSpeed(8); ship.setFirerate(200); - while (window.isOpen()) { - window.clear(); + while (mainWindow.isOpen()) { +// std::cout << "Liczba: " << RandomNumberGenerator::getRandomNumber(0,499) << std::endl; + mainWindow.clear(); // Tu są handlowane eventy sf::Event event{}; - while (window.pollEvent(event)) { + while (mainWindow.pollEvent(event)) { if(event.type == sf::Event::Closed) - window.close(); + mainWindow.close(); if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) { - window.close(); + mainWindow.close(); } if(sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) { ship.shoot(); @@ -60,43 +64,105 @@ int main() if(sf::Keyboard::isKeyPressed(sf::Keyboard::A)) { - if(ship.getPosition().x > -10) { + if(ship.getPosition().x > 50) { ship.moveLeft(); } } - if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) { - if(ship.getPosition().x < 480) { - ship.moveRight(); - } - } if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) { - if(ship.getPosition().y > 0) { + if(ship.getPosition().y > 80) { ship.moveUp(); } } if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) { - if(ship.getPosition().y < 700) { + if(ship.getPosition().y < 720) { ship.moveDown(); } } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) { + if(ship.getPosition().x < 550) { + ship.moveRight(); + } + } + if(sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) { + ship.shoot(); + } + + + if(sf::Mouse::isButtonPressed(sf::Mouse::Left)) ship.shoot(); + if(sf::Mouse::isButtonPressed(sf::Mouse::Right)) ship.alternate_shoot(); + + // Generate a new meteor at a random position at the top of the screen + plansza.spawn_meteor(); + + + // Update and draw meteors + for (auto& meteor : plansza.getMeteors()) { + meteor.update(); + mainWindow.draw(meteor.getSprite()); + } for (auto& bullet : ship.getBullets()) { bullet.update(); - window.draw(bullet.getSprite()); + mainWindow.draw(bullet.getSprite()); } // tło background.update(); - background.draw(window); + background.draw(mainWindow); - for (auto& bullet : ship.getBullets()) { - bullet.update(); - window.draw(bullet.getSprite()); + + plansza.update_meteors(); + ship.updateBullets(); + mainWindow.draw(ship.getSprite()); + + // trochę dziwny sposób ale jednak działa + for (auto& meteor : plansza.getMeteors()) { + if(ship.getSprite().getGlobalBounds().intersects(meteor.getSprite().getGlobalBounds())) { + 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"; + return -1; + } + sf::Text text("Your ship is destroyed!", font, 24); + text.setFillColor(sf::Color::Red); + text.setPosition(50, 80); + + while (errorWindow.isOpen()) { + sf::Event event; + while (errorWindow.pollEvent(event)) { + if (event.type == sf::Event::Closed || sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) { + errorWindow.close(); + mainWindow.close(); + exit(-2); + } + } + errorWindow.clear(); + errorWindow.draw(text); + errorWindow.display(); + } + } } - ship.updateBullets(); - window.draw(ship.getSprite()); - window.display(); + for (auto meteorIt = plansza.getMeteors().begin(); meteorIt != plansza.getMeteors().end(); ) { + bool meteorHit = false; + for (auto bulletIt = ship.getBullets().begin(); bulletIt != ship.getBullets().end(); ) { + if (meteorIt->getSprite().getGlobalBounds().intersects(bulletIt->getSprite().getGlobalBounds())) { + bulletIt = ship.getBullets().erase(bulletIt); + meteorIt = plansza.getMeteors().erase(meteorIt); + meteorHit = true; + break; // Exit the inner loop to avoid invalidating the iterator + } else { + ++bulletIt; + } + } + if (!meteorHit) { + ++meteorIt; + } + } + + mainWindow.display(); } return 0; diff --git a/sources/Actor.cpp b/sources/Actor.cpp index afe34e4..ae74aff 100644 --- a/sources/Actor.cpp +++ b/sources/Actor.cpp @@ -1,11 +1,11 @@ #include "../headers/Actor.h" -// TODO: Naprawić krzywy sprite statku Actor::Actor(int x, int y, std::string path) { loadTexture(path); position.x = x; position.y = y; - actorSprite.setPosition(x, y); + actorSprite.setOrigin(actorSprite.getLocalBounds().width / 2, actorSprite.getLocalBounds().height / 2); // wycentrowanie sprite + actorSprite.setPosition(float(x), float(y)); } void Actor::loadTexture(std::string path) { @@ -13,7 +13,7 @@ void Actor::loadTexture(std::string path) { actorSprite.setTexture(actorTexture); bulletTextureLeft.loadFromFile("../assets/img/bullet_left.png"); - bulletTextureRight.loadFromFile("../assets/img/bullet_right.png"); + bulletTextureRight.loadFromFile("../assets/img/Rocket_111.png"); } sf::Sprite &Actor::getSprite() { @@ -25,7 +25,7 @@ Position Actor::getPosition() { } void Actor::shoot() { - bullets.emplace_back(float(position.x) + actorSprite.getGlobalBounds().width / 2-62, position.y, bulletTextureLeft); + bullets.emplace_back(float(position.x) + actorSprite.getGlobalBounds().width / 2, position.y, bulletTextureLeft); } std::vector &Actor::getBullets() { @@ -39,3 +39,7 @@ void Actor::updateBullets() { } } } + +void Actor::setMovingSpeed(float speed) { + moving_speed = speed; +} diff --git a/sources/Bullet.cpp b/sources/Bullet.cpp index c897f7d..dc9f8a6 100644 --- a/sources/Bullet.cpp +++ b/sources/Bullet.cpp @@ -1,13 +1,15 @@ #include #include "../headers/Bullet.h" -Bullet::Bullet(float x, float y, sf::Texture &bulletTexture) { - outOfBounds = false; - bulletSprite.setTexture(bulletTexture); - bulletSprite.setPosition(x, y); - bulletSpeed = -10.0f; +Bullet::Bullet(float x, float y, sf::Texture &texture) { bulletPosition.x = x; bulletPosition.y = y; + outOfBounds = false; + bulletTexture = texture; + bulletSprite.setTexture(texture); + bulletSprite.setOrigin(bulletSprite.getLocalBounds().width/2, bulletSprite.getLocalBounds().height/2); + bulletSprite.setPosition(x, y); + bulletSpeed = -10.0f; } void Bullet::setSpeed(float speed) { diff --git a/sources/Meteor.cpp b/sources/Meteor.cpp new file mode 100644 index 0000000..996d402 --- /dev/null +++ b/sources/Meteor.cpp @@ -0,0 +1,43 @@ +#include +#include "../headers/Meteor.h" + +Meteor::Meteor(float x, float y, sf::Texture &texture) { + outOfBounds = false; + meteorTexture = texture; + meteorSprite.setTexture(texture); + meteorSprite.setOrigin(meteorSprite.getLocalBounds().width / 2, meteorSprite.getLocalBounds().height / 2); // wycentrowanie sprite + meteorSprite.setPosition(x, y); + meteorSpeed = 5.0f; + meteorSprite.scale(0.05f, 0.05f); + meteorPosition.x = x; + meteorPosition.y = y; + meteorRotationSpeed = static_cast(rand() % 2 + 1) * (rand() % 2 == 0 ? 1 : -1); +} + +sf::Sprite &Meteor::getSprite() { + return meteorSprite; +} + +void Meteor::update() { + meteorSprite.move(0.0f, meteorSpeed); // przesunięcie sprajta + meteorPosition.y += int(meteorSpeed); // przesunięcie pozycji + meteorSprite.rotate(meteorRotationSpeed); // obracanie tym meteorkiem pięknym + if(meteorPosition.y > 900) { + outOfBounds = true; // jeżeli wyszedł poza granice ekranu ustaw tą zmienną + } +// std::cout << "x: " << meteorSprite.getPosition().x << std::endl; +// std::cout << "y: " << meteorSprite.getPosition().y << std::endl; +} + +bool Meteor::getStatus() { + return outOfBounds; +} + +unsigned int Meteor::counter = 0; + +// było użyte do testowania czy meteoryt jest kasowany +//Meteor::~Meteor() { +// Meteor::counter++; +// std::clog << Meteor::counter << " Meteor destroyed\n"; +//} + diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index d9794c6..6057327 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -1 +1,41 @@ +#include +#include #include "../headers/Plansza.h" + +Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth) { + size.height = windowHeight; + size.width = windowWidth; + meteorTexture1.loadFromFile("../assets/img/meteor-1.png"); + meteorTexture2.loadFromFile("../assets/img/meteor-2.png"); + spawnClock.restart(); +} + +void Plansza::spawn_meteor() { + if (spawnClock.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 + if(rand() % 2 == 1) { + meteors.emplace_back(RandomNumberGenerator::getRandomNumber(0,499), -100, meteorTexture2); + } else { + meteors.emplace_back(RandomNumberGenerator::getRandomNumber(0,499), -100, meteorTexture1); + } + } + spawnClock.restart(); + } +} + +Plansza::Size Plansza::getSize() { + return size; +} + +std::vector &Plansza::getMeteors() { + return meteors; +} + +void Plansza::update_meteors() { + // usuwanie meteorów które wyleciały poza ekran + for (auto& meteor : meteors) { + if(meteor.getStatus()) { + meteors.erase(meteors.begin()); + } + } +} diff --git a/sources/Player.cpp b/sources/Player.cpp index eca9dc5..08233c1 100644 --- a/sources/Player.cpp +++ b/sources/Player.cpp @@ -5,7 +5,7 @@ Player::Player(int x, int y, std::string path) : Actor(x, y, path) {}; void Player::shoot() { auto now = std::chrono::steady_clock::now(); if (std::chrono::duration_cast(now - lastShotTime).count() >= firerate) { - bullets.emplace_back(float(position.x) + actorSprite.getGlobalBounds().width / 2-62, position.y, bulletTextureLeft); + bullets.emplace_back(position.x, position.y, bulletTextureLeft); lastShotTime = now; } } @@ -13,7 +13,7 @@ void Player::shoot() { void Player::alternate_shoot() { auto now = std::chrono::steady_clock::now(); if (std::chrono::duration_cast(now - lastShotTime).count() >= firerate) { - bullets.emplace_back(float(position.x) + actorSprite.getGlobalBounds().width / 2-62, position.y, bulletTextureRight); + bullets.emplace_back(position.x, position.y, bulletTextureRight).getSprite().scale(1.5f, 1.5f); lastShotTime = now; } } @@ -28,20 +28,20 @@ void Player::move(float deltaX, float deltaY) { void Player::moveLeft() { move(-moving_speed, 0.0f); - position.x -= moving_speed; + position.x -= static_cast(moving_speed); } void Player::moveRight() { move(moving_speed, 0.0f); - position.x += moving_speed; + position.x += static_cast(moving_speed); } void Player::moveUp() { move(0.0f, -moving_speed); - position.y -= moving_speed; + position.y -= static_cast(moving_speed); } void Player::moveDown() { move(0.0f, moving_speed); - position.y += moving_speed; + position.y += static_cast(moving_speed); } \ No newline at end of file