diff --git a/sem2/SheykoOA_Homework/Dino Game/Battlefield.h b/sem2/SheykoOA_Homework/Dino Game/Battlefield.h new file mode 100644 index 00000000..34327328 --- /dev/null +++ b/sem2/SheykoOA_Homework/Dino Game/Battlefield.h @@ -0,0 +1,354 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "SFML/Graphics.hpp" +#include "Dino.h" +#include "Player.h" +#include "DinoType.h" +#include "Button.h" + +class Battlefield { +private: + Player& player; + Player& enemy; + + sf::RenderWindow& window; + + GameState& gameState; + + sf::Vector2f gridPosition; // + sf::Vector2f gridSize; // + sf::Vector2f cardSize; // + sf::Vector2f cardSpacing; // + int cardsPerRow; // + + void recieveReward(int reward) { + player.balance += reward; + } + + void showBattleResult(bool playerWon, int prize) { + + player.saveDinosToFile("dinos.txt"); + gameState = BattleResult; + recieveReward(prize); + + sf::Texture backgroundTexture; + backgroundTexture = TextureLoader::getInstance().getTexture("GameData/Plain.png"); + sf::Sprite backgroundSprite(backgroundTexture); + + sf::Font font; + font.loadFromFile("GameData/FuturaMediumC.otf"); + + sf::Text resultText; + resultText.setFont(font); + resultText.setFillColor(sf::Color::White); + resultText.setOutlineColor(sf::Color::Black); + resultText.setOutlineThickness(2.f); + resultText.setCharacterSize(64); + resultText.setString(playerWon ? "Victory!" : "Defeat!"); + resultText.setPosition(550, 200); + + sf::Text prizeText; + prizeText.setFont(font); + prizeText.setFillColor(sf::Color::White); + prizeText.setOutlineColor(sf::Color::Black); + prizeText.setOutlineThickness(2.f); + prizeText.setCharacterSize(32); + prizeText.setString("You won " + std::to_string(prize) + " coins!"); + prizeText.setPosition(500, 280); + + sf::Texture buttonTexture; + buttonTexture = TextureLoader::getInstance().getTexture("GameData/Button.png"); + Button selectDinoButton(300, 400, 300, 75, font, "Select Dinos", buttonTexture); + Button backButton(700, 400, 300, 75, font, "Menu", buttonTexture); + + while (window.isOpen() && gameState == BattleResult) { + sf::Event event; + while (window.pollEvent(event)) { + if (event.type == sf::Event::Closed) { + window.close(); + } + if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) { + sf::Vector2f mousePos(sf::Mouse::getPosition(window)); + + if (selectDinoButton.isMouseOver(window)) { + gameState = SelectingDinos; + return; + } + + if (backButton.isMouseOver(window)) { + gameState = InMenu; + return; + } + } + } + + window.clear(sf::Color::White); + window.draw(backgroundSprite); + window.draw(resultText); + window.draw(prizeText); + selectDinoButton.draw(window); + backButton.draw(window); + window.display(); + } + + + } + + +public: + + Battlefield(Player& p1, Player& p2, sf::RenderWindow& window, GameState& gameState) : player(p1), enemy(p2), window(window), gameState(gameState) { + enemy.randomDinoPull(); + gridPosition = sf::Vector2f(50, 100); // + gridSize = sf::Vector2f(800, 600); // + cardSize = sf::Vector2f(200, 300); // + cardSpacing = sf::Vector2f(70, 10); // + cardsPerRow = 4; // + } + + void drawDinoCards() { + sf::Vector2f currentPosition = gridPosition; + int currentColumn = 0; + + for (Dino* dino : player.dinos) { + if (dino->isSelected) + continue; + + + dino->draw(window, currentPosition); + + currentColumn++; + if (currentColumn >= cardsPerRow) { + currentColumn = 0; + currentPosition.x = gridPosition.x; + currentPosition.y += cardSize.y + cardSpacing.y; + } + else { + currentPosition.x += cardSize.x + cardSpacing.x; + } + } + } + + + void dinosSelection() { + if (player.dinos.size() < 3) { + gameState = InMenu; + return; + } + + sf::Texture backgroundTexture; + backgroundTexture = TextureLoader::getInstance().getTexture("GameData/Plain.png"); + sf::Sprite backgroundSprite(backgroundTexture); + + sf::Font font; + font.loadFromFile("GameData/FuturaMediumC.otf"); + + sf::Text headerText; + headerText.setFont(font); + headerText.setFillColor(sf::Color::White); + headerText.setOutlineColor(sf::Color::Black); + headerText.setOutlineThickness(2.f); + headerText.setCharacterSize(64); + headerText.setString("Select 3 dinos for battle:"); + headerText.setPosition(50, 5); + + sf::Texture buttonTexture; + buttonTexture = TextureLoader::getInstance().getTexture("GameData/Button.png"); + Button backButton(1050, 20, 200, 50, font, "Back", buttonTexture); + + while (window.isOpen() && player.selectedDinos.size() < 3) { + sf::Event event; + while (window.pollEvent(event)) { + if (event.type == sf::Event::Closed) { + window.close(); + } + if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) { + sf::Vector2f mousePos(sf::Mouse::getPosition(window)); + + // " " + if (backButton.isMouseOver(window)) { + gameState = InMenu; + return; + } + + for (Dino* dino : player.dinos) { + if (dino->sprite.getGlobalBounds().contains(mousePos)) { + if (!dino->isSelected && player.selectedDinos.size() < 3) { + dino->isSelected = true; + player.selectedDinos.push_back(dino); + } + } + } + } + } + + window.clear(sf::Color::White); + window.draw(backgroundSprite); + window.draw(headerText); + drawDinoCards(); // + backButton.draw(window); + window.display(); + } + + if (player.selectedDinos.size() == 3) { + gameState = Battle; + } + } + + void dinosShowcase() { + sf::Texture backgroundTexture; + backgroundTexture.loadFromFile("GameData/Plain.png"); + sf::Sprite backgroundSprite(backgroundTexture); + + sf::Font font; + font.loadFromFile("GameData/FuturaMediumC.otf"); + + sf::Text headerText; + headerText.setFont(font); + headerText.setFillColor(sf::Color::White); + headerText.setOutlineColor(sf::Color::Black); + headerText.setOutlineThickness(2.f); + headerText.setCharacterSize(64); + headerText.setString("My Dinos:"); + headerText.setPosition(50, 5); + + sf::Texture buttonTexture; + buttonTexture = TextureLoader::getInstance().getTexture("GameData/Button.png"); + Button backButton(1050, 20, 200, 50, font, "Back", buttonTexture); + + while (window.isOpen() && player.selectedDinos.size() < 3) { + sf::Event event; + while (window.pollEvent(event)) { + if (event.type == sf::Event::Closed) { + window.close(); + } + if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) { + sf::Vector2f mousePos(sf::Mouse::getPosition(window)); + + // " " + if (backButton.isMouseOver(window)) { + gameState = InMenu; + return; + } + } + } + + window.clear(sf::Color::White); + window.draw(backgroundSprite); + window.draw(headerText); + drawDinoCards(); // + backButton.draw(window); + window.display(); + } + } + + + void battleProcess() { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution distr(0, 2); + Terrain terrain = static_cast(distr(gen)); + + sf::Texture backgroundTexture; + switch (terrain) { + case Plain: + backgroundTexture.loadFromFile("GameData/Plain.png"); + break; + case River: + backgroundTexture.loadFromFile("GameData/River.png"); + break; + case Mountain: + backgroundTexture.loadFromFile("GameData/Mountain.png"); + break; + } + sf::Sprite backgroundSprite(backgroundTexture); + sf::Text headerText; + sf::Font font; + font.loadFromFile("GameData/FuturaMediumC.otf"); + headerText.setFont(font); // font - + headerText.setFillColor(sf::Color::White); + headerText.setOutlineColor(sf::Color::Black); + headerText.setOutlineThickness(2.f); + headerText.setCharacterSize(64); + + headerText.setPosition(50, 5); // + + sf::Clock attackClock; + sf::Clock agonyClock; + bool playerTurn = true; + + int enemyPullPrice = 0; + for (Dino* dino : enemy.selectedDinos) + enemyPullPrice += dino->cost; + + while (window.isOpen() && !player.selectedDinos.empty() && !enemy.selectedDinos.empty()) { + headerText.setString(playerTurn ? "Enemy Turn!" : "Your Turn!"); + window.clear(sf::Color::White); + window.draw(backgroundSprite); + window.draw(headerText); + + for (int i = 0; i < player.selectedDinos.size() - 1; i++) { + player.selectedDinos[i]->draw(window, sf::Vector2f(100 + i * 150, 350), false, true, 0.7); + } + for (int i = 0; i < enemy.selectedDinos.size() - 1; i++) { + enemy.selectedDinos[i]->draw(window, sf::Vector2f(900 + i * 150, 350), false, false, 0.7); + } + + player.selectedDinos.back()->draw(window, sf::Vector2f(450, 300), false, true, 1.35); + enemy.selectedDinos.back()->draw(window, sf::Vector2f(750, 300), false, false, 1.35); + + if (agonyClock.getElapsedTime().asSeconds() > 1) { + if (enemy.selectedDinos.back()->isDead) + enemy.selectedDinos.pop_back(); + + if (player.selectedDinos.back()->isDead) { + player.deleteDino(player.selectedDinos.back()); + player.selectedDinos.pop_back(); + } + + } + + if (attackClock.getElapsedTime().asSeconds() > 2) { + attackClock.restart(); + + + if (playerTurn) { + player.attackEnemy(enemy, enemy.selectedDinos, terrain); + if (enemy.selectedDinos.back()->isDead) + agonyClock.restart(); + } + else { + enemy.attackEnemy(player, player.selectedDinos, terrain); + if (player.selectedDinos.back()->isDead) + agonyClock.restart(); + } + + playerTurn = !playerTurn; // + } + + window.display(); + } + if (player.selectedDinos.empty()) { + showBattleResult(false, 100); + } + else if (enemy.selectedDinos.empty()) { + showBattleResult(true, enemyPullPrice); + } + + + } + + + + +}; diff --git a/sem2/SheykoOA_Homework/Dino Game/Button.h b/sem2/SheykoOA_Homework/Dino Game/Button.h new file mode 100644 index 00000000..549e3059 --- /dev/null +++ b/sem2/SheykoOA_Homework/Dino Game/Button.h @@ -0,0 +1,49 @@ +#pragma once + +#include + + +#include "SFML/Graphics.hpp" + +class Button { +private: + sf::Sprite sprite; + +public: + sf::Text text; + + Button(int x, int y, int width, int height, sf::Font& font, std::string buttonText, const sf::Texture& texture) { + sprite.setTexture(texture); + sprite.setPosition(sf::Vector2f(x, y)); + sprite.setScale( + static_cast(width) / texture.getSize().x, + static_cast(height) / texture.getSize().y + ); + + text.setFont(font); + text.setString(buttonText); + text.setCharacterSize(36); + text.setStyle(sf::Text::Bold); + text.setFillColor(sf::Color::White); + text.setOutlineColor(sf::Color::Black); + text.setOutlineThickness(1.0f); + + sf::FloatRect textRect = text.getLocalBounds(); + text.setOrigin(textRect.left + textRect.width / 2.0f, textRect.top + textRect.height / 2.0f); + text.setPosition(x + width / 2.0f, y + height / 2.0f); + } + + void draw(sf::RenderWindow& window) { + window.draw(sprite); + window.draw(text); + } + + bool isMouseOver(sf::RenderWindow& window) { + sf::Vector2i mousePos = sf::Mouse::getPosition(window); + sf::Vector2f buttonPos = sprite.getPosition(); + sf::Vector2f buttonSize = sf::Vector2f(sprite.getGlobalBounds().width, sprite.getGlobalBounds().height); + + return (mousePos.x >= buttonPos.x && mousePos.x <= buttonPos.x + buttonSize.x && + mousePos.y >= buttonPos.y && mousePos.y <= buttonPos.y + buttonSize.y); + } +}; \ No newline at end of file diff --git a/sem2/SheykoOA_Homework/Dino Game/Dino.h b/sem2/SheykoOA_Homework/Dino Game/Dino.h new file mode 100644 index 00000000..45ff1dce --- /dev/null +++ b/sem2/SheykoOA_Homework/Dino Game/Dino.h @@ -0,0 +1,251 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "SFML/Graphics.hpp" +#include "DinoType.h" +#include "TextureLoader.h" + +class Dino { +private: + std::string fileName; + sf::Sprite cardSprite; + sf::Font font; + sf::Text nameText; + sf::Text HPText; + sf::Texture texture; + sf::Texture attackTexture; + sf::Texture cardTexture; + sf::Color originalColor; + sf::Clock damageClock; + sf::Clock attackClock; + bool isDamaged; + bool isAttacking; + + void organizeText(sf::Text& text, std::string textString, sf::Vector2f position) { + text.setFont(font); + text.setString(textString); + text.setCharacterSize(24); + text.setPosition(position); + text.setOutlineColor(sf::Color::Black); + text.setOutlineThickness(2.f); + } + + std::string getDinoName(DinoType type) { + switch (type) { + case Tyrannosaur: + return "Tyrannosaur"; + case Brachiosaur: + return "Brachiosaur"; + case Triceratops: + return "Triceratops"; + default: + return "Dino"; + } + } + + void update() { + if (isDamaged && damageClock.getElapsedTime().asSeconds() > 1) { + sprite.setColor(originalColor); + isDamaged = false; + } + if (isAttacking && attackClock.getElapsedTime().asSeconds() <= 1) { + sprite.setTexture(attackTexture); + } + else { + sprite.setTexture(texture); + isAttacking = false; + } + if (isDead) { + rotateAfterDeath(); + } + } + +protected: + int STR = 30; + int DEX = 15; + int INT = 10; + +public: + int HP = 100; + int cost = 0; + DinoType type; + sf::Sprite sprite; + sf::Sprite attackSprite; + bool isSelected = false; + bool isDead = false; + + bool receiveDamageAndCheckDeath(int damage) { + HP -= damage; + isDamaged = true; + damageClock.restart(); + sprite.setColor(sf::Color::Red); + + if (HP <= 0) { + HP = 0; + return true; + } + return false; + } + + int attackDamage = 10; + + Dino(DinoType type) : type(type) { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution distr(10, 30); + + STR = distr(gen); + DEX = distr(gen); + INT = distr(gen); + + font.loadFromFile("GameData/FuturaMediumC.otf"); + + switch (type) { + case DinoType::Triceratops: + texture = TextureLoader::getInstance().getTexture("GameData/DinoSprites/TRIC.png"); + attackTexture.loadFromFile("GameData/DinoSprites/TRIC_A.png"); + fileName = "Triceratops.txt"; + cost = 200; + HP = 135; + break; + case DinoType::Tyrannosaur: + texture = TextureLoader::getInstance().getTexture("GameData/DinoSprites/TREX.png"); + attackTexture.loadFromFile("GameData/DinoSprites/TREX_A.png"); + fileName = "Tyrannosaur.txt"; + cost = 150; + HP = 110; + break; + case DinoType::Brachiosaur: + texture = TextureLoader::getInstance().getTexture("GameData/DinoSprites/BRA.png"); + attackTexture.loadFromFile("GameData/DinoSprites/BRA_A.png"); + fileName = "Brachiosaur.txt"; + cost = 100; + HP = 100; + break; + default: + std::cerr << "Unknown dino type" << std::endl; + return; + } + + cardTexture = TextureLoader::getInstance().getTexture("GameData/Card.png"); + cardSprite.setTexture(cardTexture); + cardSprite.setScale(1.0f, 1.1f); + cardSprite.setPosition(0, 30); + + sprite.setTexture(texture); + sprite.setScale(0.5f, 0.5f); + sprite.setPosition(0, 40); + + attackSprite.setTexture(attackTexture); + attackSprite.setScale(0.5f, 0.5f); + attackSprite.setPosition(0, 40); + + isDamaged = false; + isAttacking = false; + originalColor = sprite.getColor(); + } + + void draw(sf::RenderWindow& window, sf::Vector2f position) { + organizeText(nameText, getDinoName(type), sf::Vector2f(0, 40)); + organizeText(HPText, std::to_string(HP) + " HP", sf::Vector2f(0, 25)); + + cardSprite.setPosition(position); + sprite.setPosition(position.x, position.y + 65); + sprite.setScale(0.5f, 0.5f); + nameText.setPosition(sf::Vector2f(position.x + 20, position.y + 25)); + HPText.setPosition(sf::Vector2f(position.x + 20, position.y + 45)); + + update(); + + window.draw(cardSprite); + window.draw(sprite); + window.draw(nameText); + window.draw(HPText); + } + + void draw(sf::RenderWindow& window, sf::Vector2f position, bool drawCard, bool invert, float scaleMultiplier) { + organizeText(nameText, getDinoName(type), sf::Vector2f(0, 0)); + organizeText(HPText, std::to_string(HP) + " HP", sf::Vector2f(0, 25)); + + cardSprite.setPosition(position); + sprite.setPosition(invert ? position.x + 90 : position.x, position.y + 45); + sprite.setScale(invert ? -0.5f : 0.5f, 0.5f); + sprite.setScale(sprite.getScale() * scaleMultiplier); + + nameText.setPosition(position); + HPText.setPosition(sf::Vector2f(position.x, position.y + 25)); + + update(); + + if (drawCard) { + window.draw(cardSprite); + } + window.draw(sprite); + if (scaleMultiplier > 1.0f) { + window.draw(nameText); + window.draw(HPText); + } + } + + void triggerAttack() { + isAttacking = true; + attackClock.restart(); + } + + void rotateAfterDeath() { + sprite.setColor(sf::Color::Color(0, 0, 0, 220)); + } + + virtual ~Dino() {} + + virtual int damage(Terrain terrain) = 0; +}; + + +class DinoStr : public Dino { +public: + DinoStr(DinoType type) : Dino(type) {} + + int damage(Terrain terrain) override { + attackDamage = STR; + if (terrain == Plain) + attackDamage *= 2; + return attackDamage; + } + +}; + +class DinoDex : public Dino { +public: + DinoDex(DinoType type) : Dino(type) {} + + int damage(Terrain terrain) override { + attackDamage = DEX; + if (terrain == River) + attackDamage *= 2; + return attackDamage; + } + +}; + +class DinoInt : public Dino { +public: + DinoInt(DinoType type) : Dino(type) {} + + int damage(Terrain terrain) override { + attackDamage = INT; + if (terrain == Mountain) + attackDamage *= 2; + return attackDamage; + } + +}; \ No newline at end of file diff --git a/sem2/SheykoOA_Homework/Dino Game/DinoGame.cpp b/sem2/SheykoOA_Homework/Dino Game/DinoGame.cpp new file mode 100644 index 00000000..b0054976 --- /dev/null +++ b/sem2/SheykoOA_Homework/Dino Game/DinoGame.cpp @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "SFML/Graphics.hpp" + +#include "Button.h" +#include "Player.h" +#include "Shop.h" +#include "Battlefield.h" +#include "TextureLoader.h" + + +using namespace std; + + +void drawMainMenu(sf::RenderWindow& window, sf::Font& font, std::vector