diff --git a/src/Rpg/gamengine/RPGEngine.cpp b/src/Rpg/gamengine/RPGEngine.cpp index e17f766..a1edf9a 100755 --- a/src/Rpg/gamengine/RPGEngine.cpp +++ b/src/Rpg/gamengine/RPGEngine.cpp @@ -148,6 +148,7 @@ RPGEngine::RPGEngine(sf::RenderWindow& window, GameManager* gameManager) mAvailableTowers.push_back(2); mAvailableTowers.push_back(1); + mAvailableTowers.push_back(3); // Testing std::unique_ptr woodItem = std::make_unique(); diff --git a/src/Rpg/menues/StartTowerDefenseMenu.cpp b/src/Rpg/menues/StartTowerDefenseMenu.cpp index edb6b4d..57b4d86 100644 --- a/src/Rpg/menues/StartTowerDefenseMenu.cpp +++ b/src/Rpg/menues/StartTowerDefenseMenu.cpp @@ -176,6 +176,8 @@ void StartTowerDefenseMenu::render(sf::RenderWindow& window) { mTowerSlots[i].setFillColor(sf::Color::Green); else if (mSelectedTowers[i] == 2) mTowerSlots[i].setFillColor(sf::Color::Red); + else if (mSelectedTowers[i] == 3) + mTowerSlots[i].setFillColor(sf::Color::Cyan); } else { mTowerSlots[i].setFillColor(sf::Color(0, 0, 0, 220)); } @@ -188,6 +190,8 @@ void StartTowerDefenseMenu::render(sf::RenderWindow& window) { mSelectingTowerSlots[i].setFillColor(sf::Color::Green); else if (mAvailableTowers[i] == 2) mSelectingTowerSlots[i].setFillColor(sf::Color::Red); + else if (mAvailableTowers[i] == 3) + mSelectingTowerSlots[i].setFillColor(sf::Color::Cyan); } else { mSelectingTowerSlots[i].setFillColor(sf::Color(0, 0, 0, 220)); } diff --git a/src/TowerDefense/gamengine/GameEngine.cpp b/src/TowerDefense/gamengine/GameEngine.cpp index 533eaae..8acc3ea 100644 --- a/src/TowerDefense/gamengine/GameEngine.cpp +++ b/src/TowerDefense/gamengine/GameEngine.cpp @@ -164,12 +164,24 @@ void GameEngine::processEvents() { newTower = new LaserTower(mousePos, mProjectiles); else if (mAvailableTowers[0] == 2) newTower = new FlameTurret(mousePos, mProjectiles); + else if (mAvailableTowers[0] == 3) + newTower = new ThunderRod(mousePos, mProjectiles, mEnemies); break; case 1: if (mAvailableTowers[1] == 1) newTower = new LaserTower(mousePos, mProjectiles); else if (mAvailableTowers[1] == 2) newTower = new FlameTurret(mousePos, mProjectiles); + else if (mAvailableTowers[1] == 3) + newTower = new ThunderRod(mousePos, mProjectiles, mEnemies); + break; + case 2: + if (mAvailableTowers[2] == 1) + newTower = new LaserTower(mousePos, mProjectiles); + else if (mAvailableTowers[2] == 2) + newTower = new FlameTurret(mousePos, mProjectiles); + else if (mAvailableTowers[2] == 3) + newTower = new ThunderRod(mousePos, mProjectiles, mEnemies); break; } @@ -268,12 +280,24 @@ void GameEngine::handleNonTowerClick(const sf::Vector2f& worldPos) { newTower = new LaserTower(worldPos, mProjectiles); else if (mAvailableTowers[0] == 2) newTower = new FlameTurret(worldPos, mProjectiles); + else if (mAvailableTowers[0] == 3) + newTower = new ThunderRod(worldPos, mProjectiles, mEnemies); break; case 1: - if (mAvailableTowers[0] == 1) + if (mAvailableTowers[1] == 1) newTower = new LaserTower(worldPos, mProjectiles); else if (mAvailableTowers[1] == 2) newTower = new FlameTurret(worldPos, mProjectiles); + else if (mAvailableTowers[1] == 3) + newTower = new ThunderRod(worldPos, mProjectiles, mEnemies); + break; + case 2: + if (mAvailableTowers[2] == 1) + newTower = new LaserTower(worldPos, mProjectiles); + else if (mAvailableTowers[2] == 2) + newTower = new FlameTurret(worldPos, mProjectiles); + else if (mAvailableTowers[2] == 3) + newTower = new ThunderRod(worldPos, mProjectiles, mEnemies); break; } @@ -390,18 +414,12 @@ void GameEngine::update() { // Update projectiles for (auto projectile = mProjectiles.begin(); projectile != mProjectiles.end();) { - if (projectile->getTarget() == nullptr) { - projectile = mProjectiles.erase(projectile); - continue; - } projectile->update(dt); - if (projectile->hasHitTarget()) { - projectile->getTarget()->takeDamage(projectile->getDamage()); + if (projectile->shouldRemove()) projectile = mProjectiles.erase(projectile); - } else { + else ++projectile; - } } // Update enemies diff --git a/src/TowerDefense/gamengine/GameEngine.h b/src/TowerDefense/gamengine/GameEngine.h index 0aee10d..4c2835e 100644 --- a/src/TowerDefense/gamengine/GameEngine.h +++ b/src/TowerDefense/gamengine/GameEngine.h @@ -9,6 +9,7 @@ #include "../tower/TowerMenu.h" #include "../tower/LaserTower.h" #include "../tower/FlameTurret.h" +#include "../tower/ThunderRod.h" #include "../player/Player.h" #include "../player/PlayerMenu.h" #include "../menues/SmallMenu.h" diff --git a/src/TowerDefense/projectiles/LightingChain.cpp b/src/TowerDefense/projectiles/LightingChain.cpp new file mode 100644 index 0000000..bf10963 --- /dev/null +++ b/src/TowerDefense/projectiles/LightingChain.cpp @@ -0,0 +1,36 @@ +#include "LightingChain.h" +#include +#include + +LightingChain::LightingChain(const sf::Vector2f& position, Enemy* target, float speed, float damage) + : Projectile(position, target, speed, damage) { + mLaserLine.setPrimitiveType(sf::Lines); + mLaserLine.resize(2); + + mLaserLine[0].position = position; + mLaserLine[0].color = sf::Color::Red; + + mLaserLine[1].position = target->getPosition(); + mLaserLine[1].color = sf::Color::Red; +} + +void LightingChain::update(float dt) { + if (mTarget == nullptr || mTarget->isDead()) { + mHitTarget = true; + return; + } + + mLaserLine[0].position = getPosition(); + mLaserLine[1].position = mTarget->getPosition(); + + if (checkCollision(mTarget)) { + mTarget->takeDamage(getDamage()); + mHitTarget = true; + } +} + +void LightingChain::render(sf::RenderWindow& window) { + if (!mHitTarget) + window.draw(mLaserLine); +} + diff --git a/src/TowerDefense/projectiles/LightingChain.h b/src/TowerDefense/projectiles/LightingChain.h new file mode 100644 index 0000000..a397349 --- /dev/null +++ b/src/TowerDefense/projectiles/LightingChain.h @@ -0,0 +1,14 @@ +#pragma once +#include "Projectile.h" + +class LightingChain : public Projectile { +public: + LightingChain(const sf::Vector2f& position, Enemy* target, float speed, float damage); + + void update(float dt) override; + void render(sf::RenderWindow& window) override; + +private: + sf::VertexArray mLaserLine; +}; + diff --git a/src/TowerDefense/projectiles/Projectile.cpp b/src/TowerDefense/projectiles/Projectile.cpp index 5633026..97108ec 100644 --- a/src/TowerDefense/projectiles/Projectile.cpp +++ b/src/TowerDefense/projectiles/Projectile.cpp @@ -48,7 +48,7 @@ void Projectile::update(float dt) { // Check if the projectile has hit the target if (!mHitTarget && checkCollision(mTarget)) { - //mTarget->takeDamage(mDamage); + mTarget->takeDamage(mDamage); mHitTarget = true; } } diff --git a/src/TowerDefense/projectiles/Projectile.h b/src/TowerDefense/projectiles/Projectile.h index fbb0821..cfc9cc1 100644 --- a/src/TowerDefense/projectiles/Projectile.h +++ b/src/TowerDefense/projectiles/Projectile.h @@ -13,6 +13,7 @@ class Projectile { sf::Vector2f getPosition() const; float getDamage() const; Enemy* getTarget() const; + virtual bool shouldRemove() const {return mHitTarget || !mTarget;}; protected: sf::RectangleShape mShape; @@ -21,7 +22,7 @@ class Projectile { float mDamage; bool mHitTarget; bool mAlive; - + bool checkCollision(const Enemy* target) const; }; diff --git a/src/TowerDefense/tower/FlameTurret.cpp b/src/TowerDefense/tower/FlameTurret.cpp index f5d4ff3..fe04eff 100644 --- a/src/TowerDefense/tower/FlameTurret.cpp +++ b/src/TowerDefense/tower/FlameTurret.cpp @@ -7,6 +7,8 @@ static float distance(const sf::Vector2f& a, const sf::Vector2f& b) { FlameTurret::FlameTurret(const sf::Vector2f& position, std::vector& projectiles) : Tower(position, projectiles) { + + mShape.setFillColor(sf::Color(120, 200, 50)); mRange = 100.0f; mFireRate = 2.0f; mDamage = 10.0f; @@ -28,7 +30,7 @@ void FlameTurret::update(float dt, std::vector& enemies) { float dist = distance(mShape.getPosition(), enemy.getPosition()); if (dist <= mRange) { selectedEnemy = &enemy; - fireFlame(); + fireProjectile(); mTimeSinceLastShot = 0.0f; break; } @@ -40,7 +42,7 @@ void FlameTurret::update(float dt, std::vector& enemies) { mTarget = nullptr; } -void FlameTurret::fireFlame() { +void FlameTurret::fireProjectile() { if (!mTarget) return; // Fire the flame projectile diff --git a/src/TowerDefense/tower/FlameTurret.h b/src/TowerDefense/tower/FlameTurret.h index 301f3d5..690bfdb 100644 --- a/src/TowerDefense/tower/FlameTurret.h +++ b/src/TowerDefense/tower/FlameTurret.h @@ -11,6 +11,6 @@ class FlameTurret : public Tower { void update(float dt, std::vector& enemies) override; private: - void fireFlame(); + void fireProjectile() override; }; diff --git a/src/TowerDefense/tower/ThunderRod.cpp b/src/TowerDefense/tower/ThunderRod.cpp new file mode 100644 index 0000000..03d170b --- /dev/null +++ b/src/TowerDefense/tower/ThunderRod.cpp @@ -0,0 +1,47 @@ +#include "ThunderRod.h" +#include + +static float distance(const sf::Vector2f& a, const sf::Vector2f& b) { + return std::sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); +} + +ThunderRod::ThunderRod(const sf::Vector2f& position, std::vector& projectiles, std::vector& enemies) + : Tower(position, projectiles), mMaxChains(3), mChainRange(100.f), mEnemies(enemies), + mFireCooldown(1.25f), mProjectileSpeed(200.0f), mPosition(position), mDamage(5) { + mShape.setFillColor(sf::Color::Cyan); + + mRange = 120.0f; + mFireRate = 2.25f; + mDamage = 14.0f; + mCost = 200; + + // mUpgrades.clear(); + // mUpgrades.push_back(Upgrade("Chain Damage", 200, 5, [this]() { mDamage += 5; })); + // mUpgrades.push_back(Upgrade("Chain Range", 150, 10, [this]() { mChainRange += 15.0f; })); + // mUpgrades.push_back(Upgrade("Chain Count", 300, 1, [this]() { mMaxChains++; })); +} + +void ThunderRod::update(float dt, std::vector& enemies) +{ + mFireCooldown -= dt; + if (mFireCooldown <= 0.0f) { + Enemy* closestEnemy = nullptr; + float closestDistance = mRange; + + for (auto& enemy : enemies) { + float distance = std::hypot(enemy.getPosition().x - mPosition.x, enemy.getPosition().y - mPosition.y); + if (distance < closestDistance) { + closestEnemy = &enemy; + closestDistance = distance; + } + } + + if (closestEnemy != nullptr) { + mProjectiles.emplace_back(LightingChain(mPosition, closestEnemy, mProjectileSpeed, mDamage)); + mFireCooldown = mFireRate; + } + } + + for (auto& projectile : mProjectiles) + projectile.update(dt); +} diff --git a/src/TowerDefense/tower/ThunderRod.h b/src/TowerDefense/tower/ThunderRod.h new file mode 100644 index 0000000..1e4dcf7 --- /dev/null +++ b/src/TowerDefense/tower/ThunderRod.h @@ -0,0 +1,25 @@ +#pragma once +#include "Tower.h" +#include +#include "../enemy/Enemy.h" +#include "../projectiles/LightingChain.h" +// #include "../projectilehtningProjectile.h" + +class ThunderRod : public Tower { +public: + ThunderRod(const sf::Vector2f& position, std::vector& projectiles, std::vector& enemies); + + void update(float dt, std::vector& enemies) override; +private: + int mMaxChains; + float mChainRange; + std::vector& mEnemies; + + float mFireCooldown; + float mProjectileSpeed; + sf::Vector2f mPosition; + float mDamage; + bool mIsHighDamage; + bool mIsContinuous; +}; + diff --git a/src/TowerDefense/tower/Tower.h b/src/TowerDefense/tower/Tower.h index d4a0071..75f6d2a 100644 --- a/src/TowerDefense/tower/Tower.h +++ b/src/TowerDefense/tower/Tower.h @@ -50,7 +50,7 @@ class Tower { float mDamage; std::vector& mProjectiles; - void fireProjectile(); + virtual void fireProjectile(); std::vector mUpgrades; }; diff --git a/src/TowerDefense/tower/TowerSelectionMenu.cpp b/src/TowerDefense/tower/TowerSelectionMenu.cpp index 9247cb5..b6d3063 100644 --- a/src/TowerDefense/tower/TowerSelectionMenu.cpp +++ b/src/TowerDefense/tower/TowerSelectionMenu.cpp @@ -10,6 +10,7 @@ TowerSelectionMenu::TowerSelectionMenu(std::vector& availableTowers) if (!mFont.loadFromFile("assets/fonts/gameFont.ttf")) std::cout << "Couldn't load font2 ffsk" << std::endl; + initializeHexagon(); initializeLabels(); initializeStats(); @@ -40,6 +41,8 @@ void TowerSelectionMenu::initializeLabels() { label.setString("Laser"); else if (mAvailableTowers[i] == 2) label.setString("Flame"); + else if (mAvailableTowers[i] == 3) + label.setString("Thunder"); else label.setString(""); } else { @@ -186,6 +189,8 @@ void TowerSelectionMenu::updateHover(const sf::Vector2f& mousePosition, int crys towerCost = 100; else if (mAvailableTowers[i] == 2) towerCost = 150; + else if (mAvailableTowers[i] == 3) + towerCost = 200; sf::Color normalColor; @@ -268,8 +273,10 @@ void TowerSelectionMenu::formatStats(int i) { if (mAvailableTowers[i] == 2) mTowerIcon.setFillColor(sf::Color(255, 84, 84, 255)); - else if(mAvailableTowers[i] == 1) + else if (mAvailableTowers[i] == 1) mTowerIcon.setFillColor(sf::Color::Green); + else if (mAvailableTowers[i] == 3) + mTowerIcon.setFillColor(sf::Color::Cyan); } bool TowerSelectionMenu::isPointInConvexShape(const sf::ConvexShape& shape, const sf::Vector2f& point) const {