Compare commits
29 Commits
alpha-0.0.
...
alpha-0.0.
| Author | SHA1 | Date | |
|---|---|---|---|
| 657fe761ab | |||
| 687944bf51 | |||
| 93e079ddb3 | |||
| 8171a91ed5 | |||
| 0c1824e40b | |||
| f91ab4bc83 | |||
| 1843fc6f4d | |||
| 6a51638b7e | |||
| 8351c5d09f | |||
| ee94c811e1 | |||
| 50a8269773 | |||
| 2996c88d94 | |||
| 55263fa582 | |||
| adeddee09d | |||
| f0115166c0 | |||
| c1affc36c0 | |||
| 6c4ef25abd | |||
| fd0a5e5848 | |||
| 7fb357e9c8 | |||
| 1d7a8cc66b | |||
| 070749e685 | |||
| a716e46c64 | |||
| 2e2aeb44b9 | |||
| 2df76248be | |||
| 36f1430ff2 | |||
| 2e14827f13 | |||
| c7d81de60e | |||
| f48af51dc7 | |||
| 0f328e6f81 |
@@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
#include "Towers.h"
|
#include "Towers.h"
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
#include "Team.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace game {
|
namespace game {
|
||||||
|
|
||||||
@@ -41,20 +44,22 @@ class MobStats {
|
|||||||
private:
|
private:
|
||||||
float m_Damage;
|
float m_Damage;
|
||||||
float m_Speed;
|
float m_Speed;
|
||||||
|
glm::vec2 m_Size;
|
||||||
std::uint16_t m_MoneyCost;
|
std::uint16_t m_MoneyCost;
|
||||||
std::uint16_t m_ExpCost;
|
std::uint16_t m_ExpCost;
|
||||||
std::uint16_t m_MaxLife;
|
std::uint16_t m_MaxLife;
|
||||||
std::uint16_t m_ExpReward;
|
std::uint16_t m_ExpReward;
|
||||||
public:
|
public:
|
||||||
MobStats(float damage, float speed, std::uint16_t moneyCost,
|
MobStats(float damage, float speed, glm::vec2 size, std::uint16_t moneyCost,
|
||||||
std::uint16_t expCost, std::uint16_t expReward,
|
std::uint16_t expCost, std::uint16_t expReward,
|
||||||
std::uint16_t maxLife) : m_Damage(damage), m_Speed(speed),
|
std::uint16_t maxLife) : m_Damage(damage), m_Speed(speed),
|
||||||
m_MoneyCost(moneyCost), m_ExpCost(expCost), m_MaxLife(maxLife),
|
m_Size(size), m_MoneyCost(moneyCost), m_ExpCost(expCost),
|
||||||
m_ExpReward(expReward) {
|
m_MaxLife(maxLife), m_ExpReward(expReward) {
|
||||||
}
|
}
|
||||||
|
|
||||||
float getDamage() const { return m_Damage; }
|
float getDamage() const { return m_Damage; }
|
||||||
float getMovementSpeed() const { return m_Speed; }
|
float getMovementSpeed() const { return m_Speed; }
|
||||||
|
const glm::vec2& getSize() const { return m_Size; }
|
||||||
std::uint16_t getMoneyCost() const { return m_MoneyCost; }
|
std::uint16_t getMoneyCost() const { return m_MoneyCost; }
|
||||||
std::uint16_t getExpCost() const { return m_ExpCost; }
|
std::uint16_t getExpCost() const { return m_ExpCost; }
|
||||||
std::uint16_t getExpReward() const { return m_ExpReward; }
|
std::uint16_t getExpReward() const { return m_ExpReward; }
|
||||||
@@ -71,7 +76,7 @@ const MobStats* getMobStats(MobType type, std::uint8_t level);
|
|||||||
const TowerImmunities& getMobTowerImmunities(MobType type, std::uint8_t level);
|
const TowerImmunities& getMobTowerImmunities(MobType type, std::uint8_t level);
|
||||||
const EffectImmunities& getMobEffectImmunities(MobType type, std::uint8_t level);
|
const EffectImmunities& getMobEffectImmunities(MobType type, std::uint8_t level);
|
||||||
|
|
||||||
class Mob {
|
class Mob : public utils::shape::Rectangle {
|
||||||
protected:
|
protected:
|
||||||
float m_Health;
|
float m_Health;
|
||||||
private:
|
private:
|
||||||
@@ -80,16 +85,17 @@ private:
|
|||||||
MobLevel m_Level;
|
MobLevel m_Level;
|
||||||
Direction m_Direction;
|
Direction m_Direction;
|
||||||
std::vector<EffectDuration> m_Effects;
|
std::vector<EffectDuration> m_Effects;
|
||||||
const Tower* m_LastDamage; // the tower that damaged the mob
|
const Tower* m_LastDamage; // the last tower that damaged the mob
|
||||||
|
bool m_HasReachedCastle; // if true, no need to walk anymore
|
||||||
|
|
||||||
utils::Timer m_EffectFireTimer;
|
utils::Timer m_EffectFireTimer;
|
||||||
utils::Timer m_EffectPoisonTimer;
|
utils::Timer m_EffectPoisonTimer;
|
||||||
utils::Timer m_EffectHealTimer;
|
utils::Timer m_EffectHealTimer;
|
||||||
|
|
||||||
float m_X = 0, m_Y = 0;
|
|
||||||
public:
|
public:
|
||||||
Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level),
|
Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level),
|
||||||
m_EffectFireTimer(1000), m_EffectPoisonTimer(1000), m_EffectHealTimer(1000) {
|
m_HasReachedCastle(false), m_EffectFireTimer(1000), m_EffectPoisonTimer(1000),
|
||||||
|
m_EffectHealTimer(1000) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +103,7 @@ public:
|
|||||||
|
|
||||||
virtual void tick(std::uint64_t delta);
|
virtual void tick(std::uint64_t delta);
|
||||||
|
|
||||||
virtual void OnDeath(World* world){}
|
virtual bool OnDeath(World* world) { return true; }
|
||||||
|
|
||||||
const TowerImmunities& getTowerImmunities() const { return getMobTowerImmunities(getType(), m_Level); }
|
const TowerImmunities& getTowerImmunities() const { return getMobTowerImmunities(getType(), m_Level); }
|
||||||
const EffectImmunities& getEffectImmunities() const { return getMobEffectImmunities(getType(), m_Level); }
|
const EffectImmunities& getEffectImmunities() const { return getMobEffectImmunities(getType(), m_Level); }
|
||||||
@@ -108,15 +114,11 @@ public:
|
|||||||
bool isDead() const { return m_Health <= 0; }
|
bool isDead() const { return m_Health <= 0; }
|
||||||
bool isAlive() const { return m_Health > 0; }
|
bool isAlive() const { return m_Health > 0; }
|
||||||
const Tower* getLastDamageTower() { return m_LastDamage; }
|
const Tower* getLastDamageTower() { return m_LastDamage; }
|
||||||
|
bool hasReachedEnemyCastle() { return m_HasReachedCastle; }
|
||||||
|
|
||||||
void damage(float dmg, const Tower* damager) { m_Health = std::max(0.0f, m_Health - dmg); m_LastDamage = damager; }
|
void damage(float dmg, const Tower* damager) { m_Health = std::max(0.0f, m_Health - dmg); m_LastDamage = damager; }
|
||||||
void heal(float heal) { m_Health = std::min((float)getStats()->getMaxLife(), m_Health + heal); }
|
void heal(float heal) { m_Health = std::min(static_cast<float>(getStats()->getMaxLife()), m_Health + heal); }
|
||||||
|
void setMobReachedCastle() { m_HasReachedCastle = true; } // used when mob is in front of the castle
|
||||||
float getX() const { return m_X; }
|
|
||||||
void setX(float x) { m_X = x; }
|
|
||||||
|
|
||||||
float getY() const { return m_Y; }
|
|
||||||
void setY(float y) { m_Y = y; }
|
|
||||||
|
|
||||||
bool isImmuneTo(TowerType type);
|
bool isImmuneTo(TowerType type);
|
||||||
|
|
||||||
@@ -124,11 +126,16 @@ public:
|
|||||||
void addEffect(EffectType type, float durationSec, const Tower* tower);
|
void addEffect(EffectType type, float durationSec, const Tower* tower);
|
||||||
bool hasEffect(EffectType type);
|
bool hasEffect(EffectType type);
|
||||||
|
|
||||||
|
float getTileX() { return getCenterX() - static_cast<float>(static_cast<std::int32_t>(getCenterX())); } // returns a float between 0 and 1 excluded
|
||||||
|
float getTileY() { return getCenterY() - static_cast<float>(static_cast<std::int32_t>(getCenterY())); } // returns a float between 0 and 1 excluded
|
||||||
|
|
||||||
Direction getDirection() const { return m_Direction; }
|
Direction getDirection() const { return m_Direction; }
|
||||||
void setDirection(Direction dir) { m_Direction = dir; }
|
void setDirection(Direction dir) { m_Direction = dir; }
|
||||||
protected:
|
protected:
|
||||||
void initHealth() { m_Health = (float)getStats()->getMaxLife(); }
|
void initMob() {
|
||||||
|
m_Health = static_cast<float>(getStats()->getMaxLife());
|
||||||
|
setSize(getStats()->getSize().x, getStats()->getSize().y);
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
void updateEffects(std::uint64_t delta);
|
void updateEffects(std::uint64_t delta);
|
||||||
EffectDuration& getEffect(EffectType type);
|
EffectDuration& getEffect(EffectType type);
|
||||||
@@ -138,70 +145,70 @@ typedef std::shared_ptr<Mob> MobPtr;
|
|||||||
|
|
||||||
class Zombie : public Mob {
|
class Zombie : public Mob {
|
||||||
public:
|
public:
|
||||||
Zombie(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
|
Zombie(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
|
||||||
|
|
||||||
virtual MobType getType() const { return MobType::Zombie; }
|
virtual MobType getType() const { return MobType::Zombie; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Spider : public Mob {
|
class Spider : public Mob {
|
||||||
public:
|
public:
|
||||||
Spider(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
|
Spider(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
|
||||||
|
|
||||||
virtual MobType getType() const { return MobType::Spider; }
|
virtual MobType getType() const { return MobType::Spider; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Skeleton : public Mob {
|
class Skeleton : public Mob {
|
||||||
public:
|
public:
|
||||||
Skeleton(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
|
Skeleton(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
|
||||||
|
|
||||||
virtual MobType getType() const { return MobType::Skeleton; }
|
virtual MobType getType() const { return MobType::Skeleton; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class PigMan : public Mob {
|
class PigMan : public Mob {
|
||||||
public:
|
public:
|
||||||
PigMan(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
|
PigMan(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
|
||||||
|
|
||||||
virtual MobType getType() const { return MobType::Pigman; }
|
virtual MobType getType() const { return MobType::Pigman; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Creeper : public Mob {
|
class Creeper : public Mob {
|
||||||
public:
|
public:
|
||||||
Creeper(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
|
Creeper(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
|
||||||
|
|
||||||
virtual MobType getType() const { return MobType::Creeper; }
|
virtual MobType getType() const { return MobType::Creeper; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Silverfish : public Mob {
|
class Silverfish : public Mob {
|
||||||
public:
|
public:
|
||||||
Silverfish(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
|
Silverfish(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
|
||||||
|
|
||||||
virtual MobType getType() const { return MobType::Silverfish; }
|
virtual MobType getType() const { return MobType::Silverfish; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Blaze : public Mob {
|
class Blaze : public Mob {
|
||||||
public:
|
public:
|
||||||
Blaze(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
|
Blaze(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
|
||||||
|
|
||||||
virtual MobType getType() const { return MobType::Blaze; }
|
virtual MobType getType() const { return MobType::Blaze; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Witch : public Mob {
|
class Witch : public Mob {
|
||||||
public:
|
public:
|
||||||
Witch(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
|
Witch(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
|
||||||
|
|
||||||
virtual MobType getType() const { return MobType::Witch; }
|
virtual MobType getType() const { return MobType::Witch; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Slime : public Mob {
|
class Slime : public Mob {
|
||||||
public:
|
public:
|
||||||
Slime(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
|
Slime(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
|
||||||
|
|
||||||
virtual MobType getType() const { return MobType::Slime; }
|
virtual MobType getType() const { return MobType::Slime; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Giant : public Mob {
|
class Giant : public Mob {
|
||||||
public:
|
public:
|
||||||
Giant(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
|
Giant(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
|
||||||
|
|
||||||
virtual MobType getType() const { return MobType::Giant; }
|
virtual MobType getType() const { return MobType::Giant; }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
|
||||||
|
#include "misc/Shapes.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <algorithm>
|
#include <cmath>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace game {
|
namespace game {
|
||||||
@@ -17,14 +19,33 @@ enum class TeamColor : std::int8_t {
|
|||||||
Blue
|
Blue
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Spawn {
|
class Spawn : public utils::shape::Rectangle {
|
||||||
Direction direction;
|
private:
|
||||||
std::int32_t x, y;
|
Direction m_Direction;
|
||||||
|
public:
|
||||||
|
Spawn(){
|
||||||
|
setWidth(5);
|
||||||
|
setHeight(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
Direction getDirection() const { return m_Direction; }
|
||||||
|
|
||||||
|
void setDirection(Direction direction) { m_Direction = direction; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TeamCastle {
|
struct TeamCastle : public utils::shape::Rectangle{
|
||||||
std::int32_t x, y;
|
private:
|
||||||
std::uint16_t life = 1000;
|
float m_Life;
|
||||||
|
public:
|
||||||
|
TeamCastle() : m_Life(1000) {
|
||||||
|
setWidth(5);
|
||||||
|
setHeight(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
float getLife() const { return m_Life; }
|
||||||
|
|
||||||
|
void setLife(float life) { m_Life = life; }
|
||||||
|
void damage(float damage) { m_Life = std::max(0.0f, m_Life - damage); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Team {
|
class Team {
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "misc/Time.h"
|
#include "misc/Time.h"
|
||||||
|
#include "misc/Shapes.h"
|
||||||
|
|
||||||
#include "game/Types.h"
|
#include "game/Types.h"
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
@@ -85,19 +87,18 @@ const TowerStats* getTowerStats(TowerType type, TowerLevel level);
|
|||||||
|
|
||||||
typedef std::uint16_t TowerID;
|
typedef std::uint16_t TowerID;
|
||||||
|
|
||||||
class Tower {
|
class Tower : public utils::shape::Circle {
|
||||||
private:
|
private:
|
||||||
TowerID m_ID;
|
TowerID m_ID;
|
||||||
TowerType m_Type;
|
TowerType m_Type;
|
||||||
std::int32_t m_X, m_Y;
|
|
||||||
TowerLevel m_Level{};
|
TowerLevel m_Level{};
|
||||||
PlayerID m_Builder;
|
PlayerID m_Builder;
|
||||||
protected:
|
protected:
|
||||||
utils::CooldownTimer m_Timer;
|
utils::CooldownTimer m_Timer;
|
||||||
public:
|
public:
|
||||||
Tower(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) : m_ID(id), m_Type(type), m_X(x), m_Y(y), m_Builder(builder),
|
Tower(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) : utils::shape::Circle(x + 0.5f, y + 0.5f, 0), m_ID(id), m_Type(type), m_Builder(builder),
|
||||||
m_Timer(getStats()->getDamageRate() * 1000) { // converting seconds to millis
|
m_Timer(getStats()->getDamageRate() * 1000) { // converting seconds to millis
|
||||||
|
setRadius(getStats()->getRange());
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual TowerType getType() const = 0;
|
virtual TowerType getType() const = 0;
|
||||||
@@ -109,11 +110,10 @@ public:
|
|||||||
m_Level.setPath(path);
|
m_Level.setPath(path);
|
||||||
m_Timer.setCooldown(getStats()->getDamageRate() * 1000); // converting seconds to millis
|
m_Timer.setCooldown(getStats()->getDamageRate() * 1000); // converting seconds to millis
|
||||||
m_Timer.reset();
|
m_Timer.reset();
|
||||||
|
setRadius(getStats()->getRange());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint16_t getID() const { return m_ID; }
|
std::uint16_t getID() const { return m_ID; }
|
||||||
std::int32_t getX() const { return m_X; }
|
|
||||||
std::int32_t getY() const { return m_Y; }
|
|
||||||
const TowerLevel& getLevel() const { return m_Level; }
|
const TowerLevel& getLevel() const { return m_Level; }
|
||||||
const TowerStats* getStats() const { return getTowerStats(m_Type, m_Level); }
|
const TowerStats* getStats() const { return getTowerStats(m_Type, m_Level); }
|
||||||
PlayerID getBuilder() const { return m_Builder; }
|
PlayerID getBuilder() const { return m_Builder; }
|
||||||
@@ -163,6 +163,8 @@ class ArcherTower : public LittleTower {
|
|||||||
public:
|
public:
|
||||||
ArcherTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, getType(), x, y, builder) {}
|
ArcherTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, getType(), x, y, builder) {}
|
||||||
|
|
||||||
|
constexpr static float ExplosionRadius = 1.5f;
|
||||||
|
|
||||||
virtual TowerType getType() const { return TowerType::Archer; }
|
virtual TowerType getType() const { return TowerType::Archer; }
|
||||||
virtual void tick(std::uint64_t delta, World* world);
|
virtual void tick(std::uint64_t delta, World* world);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#include "Mobs.h"
|
#include "Mobs.h"
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
|
|
||||||
|
#include "misc/ObjectNotifier.h"
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace game {
|
namespace game {
|
||||||
typedef std::pair<std::int16_t, std::int16_t> ChunkCoord;
|
typedef std::pair<std::int16_t, std::int16_t> ChunkCoord;
|
||||||
@@ -114,7 +116,23 @@ typedef std::array<Color, 2> SpawnColorPalette;
|
|||||||
|
|
||||||
typedef std::vector<TowerPtr> TowerList;
|
typedef std::vector<TowerPtr> TowerList;
|
||||||
|
|
||||||
class World {
|
class WorldListener {
|
||||||
|
public:
|
||||||
|
WorldListener(){}
|
||||||
|
|
||||||
|
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter){}
|
||||||
|
|
||||||
|
virtual void OnArrowShot(MobPtr target, Tower* shooter){}
|
||||||
|
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter){}
|
||||||
|
|
||||||
|
virtual void OnMobDamage(MobPtr target, float damage, Tower* damager){}
|
||||||
|
|
||||||
|
virtual void OnMobDead(MobPtr mob){}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef utils::ObjectNotifier<WorldListener> WorldNotifier;
|
||||||
|
|
||||||
|
class World : public WorldNotifier, public WorldListener{
|
||||||
protected:
|
protected:
|
||||||
TowerTileColorPalette m_TowerPlacePalette;
|
TowerTileColorPalette m_TowerPlacePalette;
|
||||||
Color m_WalkablePalette;
|
Color m_WalkablePalette;
|
||||||
@@ -134,6 +152,8 @@ protected:
|
|||||||
public:
|
public:
|
||||||
World(Game* game);
|
World(Game* game);
|
||||||
|
|
||||||
|
static constexpr std::uint8_t CastleWidth = 5, CastleHeight = 5;
|
||||||
|
|
||||||
bool loadMap(const protocol::WorldBeginDataPacket* worldHeader);
|
bool loadMap(const protocol::WorldBeginDataPacket* worldHeader);
|
||||||
bool loadMap(const protocol::WorldDataPacket* worldData);
|
bool loadMap(const protocol::WorldDataPacket* worldData);
|
||||||
|
|
||||||
@@ -187,10 +207,20 @@ public:
|
|||||||
const TowerList& getTowers() const { return m_Towers; };
|
const TowerList& getTowers() const { return m_Towers; };
|
||||||
TowerPtr getTowerById(TowerID tower);
|
TowerPtr getTowerById(TowerID tower);
|
||||||
|
|
||||||
// Archer Tower
|
// WorldListener
|
||||||
|
|
||||||
|
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter);
|
||||||
|
|
||||||
virtual void OnArrowShot(MobPtr target, Tower* shooter);
|
virtual void OnArrowShot(MobPtr target, Tower* shooter);
|
||||||
|
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter);
|
||||||
|
|
||||||
|
virtual void OnMobDamage(MobPtr target, float damage, Tower* source);
|
||||||
private:
|
private:
|
||||||
void moveMobs(std::uint64_t delta);
|
void moveMobs(std::uint64_t delta);
|
||||||
|
void moveMob(MobPtr mob, std::uint64_t delta);
|
||||||
|
void moveBackMob(MobPtr mob, const TeamCastle& castle);
|
||||||
|
void changeMobDirection(MobPtr mob, WalkableTilePtr tile);
|
||||||
|
bool isMobTouchingCastle(MobPtr mob, const TeamCastle& castle) const;
|
||||||
void tickMobs(std::uint64_t delta);
|
void tickMobs(std::uint64_t delta);
|
||||||
void cleanDeadMobs();
|
void cleanDeadMobs();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "misc/DataBuffer.h"
|
#include "DataBuffer.h"
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|||||||
36
include/misc/ObjectNotifier.h
Normal file
36
include/misc/ObjectNotifier.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
template <typename Listener>
|
||||||
|
class ObjectNotifier {
|
||||||
|
protected:
|
||||||
|
std::vector<Listener*> m_Listeners;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void bindListener(Listener* listener) {
|
||||||
|
m_Listeners.push_back(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unbindListener(Listener* listener) {
|
||||||
|
auto iter = std::find(m_Listeners.begin(), m_Listeners.end(), listener);
|
||||||
|
|
||||||
|
if(iter == m_Listeners.end()) return;
|
||||||
|
|
||||||
|
m_Listeners.erase(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Func, typename... Args>
|
||||||
|
void notifyListeners(Func function, Args... args) {
|
||||||
|
for (Listener* listener : m_Listeners)
|
||||||
|
std::bind(function, listener, args...)();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
} // namespace td
|
||||||
93
include/misc/Shapes.h
Normal file
93
include/misc/Shapes.h
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace utils {
|
||||||
|
namespace shape {
|
||||||
|
|
||||||
|
class Point {
|
||||||
|
private:
|
||||||
|
float m_X, m_Y;
|
||||||
|
public:
|
||||||
|
Point() : m_X(0), m_Y(0) {}
|
||||||
|
Point(float x, float y) : m_X(x), m_Y(y) {}
|
||||||
|
|
||||||
|
float getX() const { return m_X; }
|
||||||
|
float getY() const { return m_Y; }
|
||||||
|
|
||||||
|
void setX(float x) { m_X = x; }
|
||||||
|
void setY(float y) { m_Y = y; }
|
||||||
|
|
||||||
|
float distance(const Point& point) const;
|
||||||
|
float distanceSquared(const Point& point) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Circle;
|
||||||
|
|
||||||
|
class Rectangle {
|
||||||
|
private:
|
||||||
|
Point m_Center;
|
||||||
|
float m_Width, m_Height;
|
||||||
|
public:
|
||||||
|
Rectangle() {}
|
||||||
|
|
||||||
|
const Point& getCenter() const { return m_Center; }
|
||||||
|
float getCenterX() const { return m_Center.getX(); }
|
||||||
|
float getCenterY() const { return m_Center.getY(); }
|
||||||
|
|
||||||
|
float getWidth() const { return m_Width; }
|
||||||
|
float getHeight() const { return m_Height; }
|
||||||
|
|
||||||
|
Point getTopLeft() const { return { m_Center.getX() - (m_Width / 2.0f), m_Center.getY() - (m_Height / 2.0f) }; }
|
||||||
|
Point getBottomRight() const { return { m_Center.getX() + (m_Width / 2.0f), m_Center.getY() + (m_Height / 2.0f) }; }
|
||||||
|
|
||||||
|
void setCenter(const Point& center) { m_Center = center; }
|
||||||
|
void setCenterX(float x) { m_Center.setX(x); }
|
||||||
|
void setCenterY(float y) { m_Center.setY(y); }
|
||||||
|
|
||||||
|
void setSize(float width, float height) { setWidth(width); setHeight(height); }
|
||||||
|
void setWidth(float width) { m_Width = width; }
|
||||||
|
void setHeight(float height) { m_Height = height; }
|
||||||
|
|
||||||
|
bool collidesWith(const Point& point) const;
|
||||||
|
bool collidesWith(const Rectangle& rect) const;
|
||||||
|
bool collidesWith(const Circle& circle) const;
|
||||||
|
|
||||||
|
// distance from the closest side of the rectangle
|
||||||
|
float distance(const Circle& circle) const;
|
||||||
|
float distanceSquared(const Circle& circle) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Circle {
|
||||||
|
private:
|
||||||
|
Point m_Center;
|
||||||
|
float m_Radius;
|
||||||
|
public:
|
||||||
|
Circle(float x, float y, float radius) : m_Center(x, y), m_Radius(radius) {}
|
||||||
|
Circle() : m_Radius(0) {}
|
||||||
|
|
||||||
|
const Point& getCenter() const { return m_Center; }
|
||||||
|
float getCenterX() const { return m_Center.getX(); }
|
||||||
|
float getCenterY() const { return m_Center.getY(); }
|
||||||
|
|
||||||
|
float getRadius() const { return m_Radius; }
|
||||||
|
|
||||||
|
void setCenter(const Point& center) { m_Center = center; }
|
||||||
|
void setCenterX(float x) { m_Center.setX(x); }
|
||||||
|
void setCenterY(float y) { m_Center.setY(y); }
|
||||||
|
|
||||||
|
void setRadius(float radius) { m_Radius = radius; }
|
||||||
|
|
||||||
|
bool collidesWith(const Point& point) const;
|
||||||
|
bool collidesWith(const Rectangle& rect) const;
|
||||||
|
bool collidesWith(const Circle& circle) const;
|
||||||
|
|
||||||
|
// distance from the closest side of the rectangle
|
||||||
|
float distance(const Rectangle& rect) const;
|
||||||
|
float distanceSquared(const Rectangle& rect) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace shape
|
||||||
|
} // namespace utils
|
||||||
|
} // namespace td
|
||||||
@@ -39,7 +39,7 @@ public:
|
|||||||
// utililty class to call function at regular period of time
|
// utililty class to call function at regular period of time
|
||||||
class Timer {
|
class Timer {
|
||||||
private:
|
private:
|
||||||
std::uint64_t m_Interval;
|
std::uint64_t m_Interval; // in millis
|
||||||
std::uint64_t m_InternalTime = 0;
|
std::uint64_t m_InternalTime = 0;
|
||||||
public:
|
public:
|
||||||
Timer() : m_Interval(0) {}
|
Timer() : m_Interval(0) {}
|
||||||
@@ -56,7 +56,7 @@ public:
|
|||||||
// utililty class to call function at regular period of time with a cooldown (used for towers)
|
// utililty class to call function at regular period of time with a cooldown (used for towers)
|
||||||
class CooldownTimer {
|
class CooldownTimer {
|
||||||
private:
|
private:
|
||||||
std::uint64_t m_Cooldown;
|
std::uint64_t m_Cooldown; // in millis
|
||||||
std::uint64_t m_CooldownTime;
|
std::uint64_t m_CooldownTime;
|
||||||
public:
|
public:
|
||||||
CooldownTimer() : m_Cooldown(0), m_CooldownTime(0) {}
|
CooldownTimer() : m_Cooldown(0), m_CooldownTime(0) {}
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ public:
|
|||||||
|
|
||||||
void setClickPos(const glm::vec2& worldPos);
|
void setClickPos(const glm::vec2& worldPos);
|
||||||
private:
|
private:
|
||||||
static constexpr float m_TowerPopupTileWidth = 250.0f;
|
static constexpr float m_TowerPopupTileWidth = 200.0f;
|
||||||
static constexpr float m_TowerPopupTileHeight = 250.0f;
|
static constexpr float m_TowerPopupTileHeight = 200.0f;
|
||||||
|
|
||||||
static constexpr float m_PlaceTowerButtonWidth = 200.0f;
|
static constexpr float m_PlaceTowerButtonWidth = 150.0f;
|
||||||
static constexpr float m_PlaceTowerButtonHeight = 45.0f;
|
static constexpr float m_PlaceTowerButtonHeight = 35.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gui
|
} // namespace gui
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "GuiWidget.h"
|
#include "GuiWidget.h"
|
||||||
|
|
||||||
#include "misc/Updater.h"
|
#include "updater/Updater.h"
|
||||||
|
|
||||||
#include <future>
|
#include <future>
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
#define TD_VERSION "alpha-0.0.1"
|
#define TD_VERSION "alpha-0.0.3"
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace utils {
|
namespace utils {
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#include "window/Display.h"
|
#include "window/Display.h"
|
||||||
#include "misc/Updater.h"
|
#include "updater/Updater.h"
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
extern "C"
|
extern "C"
|
||||||
|
|||||||
@@ -88,66 +88,66 @@ bool Mob::hasEffect(EffectType type) {
|
|||||||
typedef std::pair<MobType, std::uint8_t> MobKey;
|
typedef std::pair<MobType, std::uint8_t> MobKey;
|
||||||
|
|
||||||
const std::map<MobKey, MobStats> MobConstants = {
|
const std::map<MobKey, MobStats> MobConstants = {
|
||||||
// damage speed money_cost exp_cost exp_reward max_health
|
// damage speed size money_cost exp_cost exp_reward max_health
|
||||||
{{MobType::Zombie, 1},{MobStats{1, 1.6, 15, 0, 7, 40}}},
|
{{MobType::Zombie, 1},{MobStats{1, 1.6, {1, 1}, 15, 0, 7, 40}}},
|
||||||
{{MobType::Zombie, 2},{MobStats{1, 1.6, 18, 88, 9, 56}}},
|
{{MobType::Zombie, 2},{MobStats{1, 1.6, {1, 1}, 18, 88, 9, 56}}},
|
||||||
{{MobType::Zombie, 3},{MobStats{1, 1.6, 22, 153, 10, 78}}},
|
{{MobType::Zombie, 3},{MobStats{1, 1.6, {1, 1}, 22, 153, 10, 78}}},
|
||||||
{{MobType::Zombie, 4},{MobStats{1.5, 1.6, 26, 268, 13, 110}}},
|
{{MobType::Zombie, 4},{MobStats{1.5, 1.6, {1, 1}, 26, 268, 13, 110}}},
|
||||||
{{MobType::Zombie, 5},{MobStats{2, 1.6, 31, 469, 15, 154}}},
|
{{MobType::Zombie, 5},{MobStats{2, 1.6, {1, 1}, 31, 469, 15, 154}}},
|
||||||
|
|
||||||
{{MobType::Spider, 1},{MobStats{1, 1.6, 25, 100, 15, 80}}},
|
{{MobType::Spider, 1},{MobStats{1, 1.6, {1, 1}, 25, 100, 15, 80}}},
|
||||||
{{MobType::Spider, 2},{MobStats{1, 2, 30, 175, 16, 112}}},
|
{{MobType::Spider, 2},{MobStats{1, 2, {1, 1}, 30, 175, 16, 112}}},
|
||||||
{{MobType::Spider, 3},{MobStats{1.5, 2, 36, 306, 18, 157}}},
|
{{MobType::Spider, 3},{MobStats{1.5, 2, {1, 1}, 36, 306, 18, 157}}},
|
||||||
{{MobType::Spider, 4},{MobStats{2.5, 2, 43, 536, 19, 222}}},
|
{{MobType::Spider, 4},{MobStats{2.5, 2, {1, 1}, 43, 536, 19, 222}}},
|
||||||
{{MobType::Spider, 5},{MobStats{1.5, 2.5, 52, 938, 22, 307}}},
|
{{MobType::Spider, 5},{MobStats{1.5, 2.5, {1, 1}, 52, 938, 22, 307}}},
|
||||||
|
|
||||||
{{MobType::Skeleton, 1},{MobStats{1, 1.6, 120, 200, 30, 350}}},
|
{{MobType::Skeleton, 1},{MobStats{1, 1.6, {1, 1}, 120, 200, 30, 350}}},
|
||||||
{{MobType::Skeleton, 2},{MobStats{1, 1.6, 144, 350, 33, 490}}},
|
{{MobType::Skeleton, 2},{MobStats{1, 1.6, {1, 1}, 144, 350, 33, 490}}},
|
||||||
{{MobType::Skeleton, 3},{MobStats{1, 1.6, 173, 613, 36, 686}}},
|
{{MobType::Skeleton, 3},{MobStats{1, 1.6, {1, 1}, 173, 613, 36, 686}}},
|
||||||
{{MobType::Skeleton, 4},{MobStats{1.5, 1.6, 225, 1072, 40, 960}}},
|
{{MobType::Skeleton, 4},{MobStats{1.5, 1.6, {1, 1}, 225, 1072, 40, 960}}},
|
||||||
{{MobType::Skeleton, 5},{MobStats{2, 1.6, 255, 1876, 43, 1345}}},
|
{{MobType::Skeleton, 5},{MobStats{2, 1.6, {1, 1}, 255, 1876, 43, 1345}}},
|
||||||
|
|
||||||
{{MobType::Pigman, 1},{MobStats{1, 2, 100, 150, 22, 150}}},
|
{{MobType::Pigman, 1},{MobStats{1, 2, {1, 1}, 100, 150, 22, 150}}},
|
||||||
{{MobType::Pigman, 2},{MobStats{1, 2, 120, 263, 24, 210}}},
|
{{MobType::Pigman, 2},{MobStats{1, 2, {1, 1}, 120, 263, 24, 210}}},
|
||||||
{{MobType::Pigman, 3},{MobStats{1, 2, 144, 459, 25, 297}}},
|
{{MobType::Pigman, 3},{MobStats{1, 2, {1, 1}, 144, 459, 25, 297}}},
|
||||||
{{MobType::Pigman, 4},{MobStats{1, 2, 173, 804, 25, 412}}},
|
{{MobType::Pigman, 4},{MobStats{1, 2, {1, 1}, 173, 804, 25, 412}}},
|
||||||
{{MobType::Pigman, 5},{MobStats{1.5, 2, 207, 1407, 27, 576}}},
|
{{MobType::Pigman, 5},{MobStats{1.5, 2, {1, 1}, 207, 1407, 27, 576}}},
|
||||||
|
|
||||||
{{MobType::Creeper, 1},{MobStats{1, 2, 250, 325, 46, 350}}},
|
{{MobType::Creeper, 1},{MobStats{1, 2, {1, 1}, 250, 325, 46, 350}}},
|
||||||
{{MobType::Creeper, 2},{MobStats{1, 2, 290, 550, 49, 460}}},
|
{{MobType::Creeper, 2},{MobStats{1, 2, {1, 1}, 290, 550, 49, 460}}},
|
||||||
{{MobType::Creeper, 3},{MobStats{2, 2, 350, 800, 55, 630}}},
|
{{MobType::Creeper, 3},{MobStats{2, 2, {1, 1}, 350, 800, 55, 630}}},
|
||||||
{{MobType::Creeper, 4},{MobStats{3, 2, 420, 1300, 61, 900}}},
|
{{MobType::Creeper, 4},{MobStats{3, 2, {1, 1}, 420, 1300, 61, 900}}},
|
||||||
{{MobType::Creeper, 5},{MobStats{4, 2, 510, 1850, 67, 1250}}},
|
{{MobType::Creeper, 5},{MobStats{4, 2, {1, 1}, 510, 1850, 67, 1250}}},
|
||||||
|
|
||||||
{{MobType::Silverfish, 1},{MobStats{1, 1.6, 38, 125, 18, 120}}},
|
{{MobType::Silverfish, 1},{MobStats{1, 1.6, {1, 1}, 38, 125, 18, 120}}},
|
||||||
{{MobType::Silverfish, 2},{MobStats{1, 1.6, 50, 230, 19, 170}}},
|
{{MobType::Silverfish, 2},{MobStats{1, 1.6, {1, 1}, 50, 230, 19, 170}}},
|
||||||
{{MobType::Silverfish, 3},{MobStats{1, 1.6, 75, 340, 25, 225}}},
|
{{MobType::Silverfish, 3},{MobStats{1, 1.6, {1, 1}, 75, 340, 25, 225}}},
|
||||||
{{MobType::Silverfish, 4},{MobStats{1.5, 1.6, 170, 700, 33, 310}}},
|
{{MobType::Silverfish, 4},{MobStats{1.5, 1.6, {1, 1}, 170, 700, 33, 310}}},
|
||||||
{{MobType::Silverfish, 5},{MobStats{1.5, 1.6, 200, 1800, 36, 390}}},
|
{{MobType::Silverfish, 5},{MobStats{1.5, 1.6, {1, 1}, 200, 1800, 36, 390}}},
|
||||||
|
|
||||||
{{MobType::Blaze, 1},{MobStats{1, 1.6, 500, 500, 105, 410}}},
|
{{MobType::Blaze, 1},{MobStats{1, 1.6, {1, 1}, 500, 500, 105, 410}}},
|
||||||
{{MobType::Blaze, 2},{MobStats{1, 1.6, 600, 875, 111, 574}}},
|
{{MobType::Blaze, 2},{MobStats{1, 1.6, {1, 1}, 600, 875, 111, 574}}},
|
||||||
{{MobType::Blaze, 3},{MobStats{1, 1.6, 720, 1531, 115, 804}}},
|
{{MobType::Blaze, 3},{MobStats{1, 1.6, {1, 1}, 720, 1531, 115, 804}}},
|
||||||
{{MobType::Blaze, 4},{MobStats{1.5, 1.6, 864, 2680, 121, 1125}}},
|
{{MobType::Blaze, 4},{MobStats{1.5, 1.6, {1, 1}, 864, 2680, 121, 1125}}},
|
||||||
{{MobType::Blaze, 5},{MobStats{2, 1.6, 1037, 4689, 127, 1575}}},
|
{{MobType::Blaze, 5},{MobStats{2, 1.6, {1, 1}, 1037, 4689, 127, 1575}}},
|
||||||
|
|
||||||
{{MobType::Witch, 1},{MobStats{1, 1.6, 150, 300, 37, 300}}},
|
{{MobType::Witch, 1},{MobStats{1, 1.6, {1, 1}, 150, 300, 37, 300}}},
|
||||||
{{MobType::Witch, 2},{MobStats{1, 1.6, 165, 525, 39, 405}}},
|
{{MobType::Witch, 2},{MobStats{1, 1.6, {1, 1}, 165, 525, 39, 405}}},
|
||||||
{{MobType::Witch, 3},{MobStats{1, 1.6, 182, 918, 42, 547}}},
|
{{MobType::Witch, 3},{MobStats{1, 1.6, {1, 1}, 182, 918, 42, 547}}},
|
||||||
{{MobType::Witch, 4},{MobStats{1.5, 1.6, 200, 1606, 43, 738}}},
|
{{MobType::Witch, 4},{MobStats{1.5, 1.6, {1, 1}, 200, 1606, 43, 738}}},
|
||||||
{{MobType::Witch, 5},{MobStats{2, 1.6, 220, 2810, 45, 996}}},
|
{{MobType::Witch, 5},{MobStats{2, 1.6, {1, 1}, 220, 2810, 45, 996}}},
|
||||||
|
|
||||||
{{MobType::Slime, 1},{MobStats{1, 0.8, 1500, 1000, 300, 800}}},
|
{{MobType::Slime, 1},{MobStats{1, 0.8, {1, 1}, 1500, 1000, 300, 800}}},
|
||||||
{{MobType::Slime, 2},{MobStats{1.5, 0.8, 1800, 1750, 314, 880}}},
|
{{MobType::Slime, 2},{MobStats{1.5, 0.8, {1, 1}, 1800, 1750, 314, 880}}},
|
||||||
{{MobType::Slime, 3},{MobStats{2, 0.8, 2160, 3063, 330, 968}}},
|
{{MobType::Slime, 3},{MobStats{2, 0.8, {1, 1}, 2160, 3063, 330, 968}}},
|
||||||
{{MobType::Slime, 4},{MobStats{2.5, 0.8, 2592, 5359, 348, 1065}}},
|
{{MobType::Slime, 4},{MobStats{2.5, 0.8, {1, 1}, 2592, 5359, 348, 1065}}},
|
||||||
{{MobType::Slime, 5},{MobStats{3, 0.8, 3110, 9379, 366, 1171}}},
|
{{MobType::Slime, 5},{MobStats{3, 0.8, {1, 1}, 3110, 9379, 366, 1171}}},
|
||||||
|
|
||||||
{{MobType::Giant, 1},{MobStats{10, 0.8, 4000, 2250, 600, 6250}}},
|
{{MobType::Giant, 1},{MobStats{10, 0.8, {1, 1}, 4000, 2250, 600, 6250}}},
|
||||||
{{MobType::Giant, 2},{MobStats{20, 0.8, 4500, 4000, 612, 9375}}},
|
{{MobType::Giant, 2},{MobStats{20, 0.8, {1, 1}, 4500, 4000, 612, 9375}}},
|
||||||
{{MobType::Giant, 3},{MobStats{30, 0.8, 5062, 7250, 624, 14062}}},
|
{{MobType::Giant, 3},{MobStats{30, 0.8, {1, 1}, 5062, 7250, 624, 14062}}},
|
||||||
{{MobType::Giant, 4},{MobStats{40, 0.8, 5695, 12500, 636, 21093}}},
|
{{MobType::Giant, 4},{MobStats{40, 0.8, {1, 1}, 5695, 12500, 636, 21093}}},
|
||||||
{{MobType::Giant, 5},{MobStats{50, 0.8, 6407, 22000, 648, 31640}}},
|
{{MobType::Giant, 5},{MobStats{50, 0.8, {1, 1}, 6407, 22000, 648, 31640}}},
|
||||||
};
|
};
|
||||||
|
|
||||||
const MobStats* getMobStats(MobType type, std::uint8_t level) {
|
const MobStats* getMobStats(MobType type, std::uint8_t level) {
|
||||||
@@ -235,7 +235,7 @@ const std::map<MobKey, EffectImmunities> MobsEffectImmunities = {
|
|||||||
|
|
||||||
{{MobType::Skeleton, 1},{}},
|
{{MobType::Skeleton, 1},{}},
|
||||||
{{MobType::Skeleton, 2},{}},
|
{{MobType::Skeleton, 2},{}},
|
||||||
{{MobType::Skeleton, 3},{EffectType::Fire}},
|
{{MobType::Skeleton, 3},{}},
|
||||||
{{MobType::Skeleton, 4},{EffectType::Fire}},
|
{{MobType::Skeleton, 4},{EffectType::Fire}},
|
||||||
{{MobType::Skeleton, 5},{EffectType::Fire}},
|
{{MobType::Skeleton, 5},{EffectType::Fire}},
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "game/Player.h"
|
#include "game/Player.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace game {
|
namespace game {
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace game {
|
|||||||
bool Tower::isMobInRange(MobPtr mob) {
|
bool Tower::isMobInRange(MobPtr mob) {
|
||||||
if (mob->isDead())
|
if (mob->isDead())
|
||||||
return false;
|
return false;
|
||||||
return (m_X - mob->getX()) * (m_X - mob->getX()) + (m_Y - mob->getY()) * (m_Y - mob->getY()) < (getStats()->getRange() * getStats()->getRange());
|
return mob->collidesWith(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<std::pair<TowerType, TowerLevel>, TowerStats> TowerConstants = {
|
const std::map<std::pair<TowerType, TowerLevel>, TowerStats> TowerConstants = {
|
||||||
@@ -21,8 +21,8 @@ const std::map<std::pair<TowerType, TowerLevel>, TowerStats> TowerConstants = {
|
|||||||
{{TowerType::Archer, {4, TowerPath::Top}}, {0.8, 0, 15}},
|
{{TowerType::Archer, {4, TowerPath::Top}}, {0.8, 0, 15}},
|
||||||
|
|
||||||
{{TowerType::Archer, {2, TowerPath::Bottom}}, {2, 10, 12}},
|
{{TowerType::Archer, {2, TowerPath::Bottom}}, {2, 10, 12}},
|
||||||
{{TowerType::Archer, {3, TowerPath::Bottom}}, {2, 0, 13}},
|
{{TowerType::Archer, {3, TowerPath::Bottom}}, {2, 10, 13}},
|
||||||
{{TowerType::Archer, {4, TowerPath::Bottom}}, {2, 0, 15}},
|
{{TowerType::Archer, {4, TowerPath::Bottom}}, {2, 10, 15}},
|
||||||
|
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
|
|
||||||
@@ -213,11 +213,11 @@ void ArcherTower::tick(std::uint64_t delta, World* world) {
|
|||||||
std::uint8_t arrows = explosiveArrows ? 2 : getLevel().getLevel();
|
std::uint8_t arrows = explosiveArrows ? 2 : getLevel().getLevel();
|
||||||
for (MobPtr mob : world->getMobList()) {
|
for (MobPtr mob : world->getMobList()) {
|
||||||
if (isMobInRange(mob)) {
|
if (isMobInRange(mob)) {
|
||||||
world->OnArrowShot(mob, this);
|
world->notifyListeners(&WorldListener::OnArcherTowerShot, mob, this);
|
||||||
|
m_Timer.applyCooldown();
|
||||||
arrowsShot++;
|
arrowsShot++;
|
||||||
if (arrowsShot >= arrows)
|
if (arrowsShot >= arrows)
|
||||||
break;
|
break;
|
||||||
m_Timer.applyCooldown();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,7 +229,8 @@ void IceTower::tick(std::uint64_t delta, World* world) {
|
|||||||
for (MobPtr mob : world->getMobList()) {
|
for (MobPtr mob : world->getMobList()) {
|
||||||
if (isMobInRange(mob)) {
|
if (isMobInRange(mob)) {
|
||||||
mob->addEffect(EffectType::Slowness, 1, this); // slowness for 1s every second
|
mob->addEffect(EffectType::Slowness, 1, this); // slowness for 1s every second
|
||||||
mob->damage(damage, this);
|
if(damage > 0)
|
||||||
|
world->notifyListeners(&WorldListener::OnMobDamage, mob, damage, this);
|
||||||
m_Timer.applyCooldown();
|
m_Timer.applyCooldown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,7 +253,7 @@ void PoisonTower::tick(std::uint64_t delta, World* world) {
|
|||||||
for (MobPtr mob : world->getMobList()) {
|
for (MobPtr mob : world->getMobList()) {
|
||||||
if (isMobInRange(mob)) {
|
if (isMobInRange(mob)) {
|
||||||
if (getLevel().getPath() == TowerPath::Bottom) {
|
if (getLevel().getPath() == TowerPath::Bottom) {
|
||||||
mob->damage(getStats()->getDamage(), this);
|
world->notifyListeners(&WorldListener::OnMobDamage, mob, getStats()->getDamage(), this);
|
||||||
} else {
|
} else {
|
||||||
float durationSec;
|
float durationSec;
|
||||||
switch (getLevel().getLevel()) {
|
switch (getLevel().getLevel()) {
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ namespace td {
|
|||||||
namespace game {
|
namespace game {
|
||||||
|
|
||||||
World::World(Game* game) : m_Game(game) {
|
World::World(Game* game) : m_Game(game) {
|
||||||
|
bindListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
TilePtr World::getTile(std::int32_t x, std::int32_t y) const {
|
TilePtr World::getTile(std::int32_t x, std::int32_t y) const {
|
||||||
std::int16_t chunkX = x / Chunk::ChunkWidth;
|
std::int16_t chunkX = x / Chunk::ChunkWidth;
|
||||||
std::int16_t chunkY = y / Chunk::ChunkHeight;
|
std::int16_t chunkY = y / Chunk::ChunkHeight;
|
||||||
|
|
||||||
std::uint16_t subChunkX = x % Chunk::ChunkWidth;
|
std::uint16_t subChunkX = std::abs(x % Chunk::ChunkWidth);
|
||||||
std::uint16_t subChunkY = y % Chunk::ChunkHeight;
|
std::uint16_t subChunkY = std::abs(y % Chunk::ChunkHeight);
|
||||||
|
|
||||||
auto chunkIt = m_Chunks.find({ chunkX, chunkY });
|
auto chunkIt = m_Chunks.find({ chunkX, chunkY });
|
||||||
if (chunkIt == m_Chunks.end())
|
if (chunkIt == m_Chunks.end())
|
||||||
@@ -111,8 +111,7 @@ void World::tick(std::uint64_t delta) {
|
|||||||
|
|
||||||
void World::spawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir) {
|
void World::spawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir) {
|
||||||
MobPtr mob = MobFactory::createMob(id, type, level, sender);
|
MobPtr mob = MobFactory::createMob(id, type, level, sender);
|
||||||
mob->setX(x);
|
mob->setCenter({ x, y });
|
||||||
mob->setY(y);
|
|
||||||
mob->setDirection(dir);
|
mob->setDirection(dir);
|
||||||
m_Mobs.push_back(mob);
|
m_Mobs.push_back(mob);
|
||||||
}
|
}
|
||||||
@@ -129,41 +128,158 @@ void World::tickMobs(std::uint64_t delta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::moveMobs(std::uint64_t delta) {
|
void World::changeMobDirection(MobPtr mob, WalkableTilePtr tile) {
|
||||||
for (MobPtr mob : m_Mobs) {
|
if (mob->getDirection() == tile->direction) return;
|
||||||
TilePtr tile = getTile(mob->getX(), mob->getY());
|
|
||||||
|
|
||||||
if (tile != nullptr && tile->getType() == TileType::Walk) {
|
float tileX = static_cast<float>(static_cast<std::int32_t>(mob->getCenterX()));
|
||||||
WalkableTile* walkTile = dynamic_cast<WalkableTile*>(tile.get());
|
float tileY = static_cast<float>(static_cast<std::int32_t>(mob->getCenterY()));
|
||||||
mob->setDirection(walkTile->direction);
|
|
||||||
|
switch (mob->getDirection()) {
|
||||||
|
|
||||||
|
case Direction::PositiveY: {
|
||||||
|
if (tile->direction == Direction::NegativeX) {
|
||||||
|
if (mob->getTileY() > mob->getTileX()) {
|
||||||
|
mob->setCenterY(tileY + mob->getTileX());
|
||||||
|
mob->setDirection(tile->direction);
|
||||||
|
}
|
||||||
|
} else { // tile->direction = Direction::PositiveX
|
||||||
|
if (mob->getTileY() > 1 - mob->getTileX()) {
|
||||||
|
mob->setCenterY(tileY + (1 - mob->getTileX()));
|
||||||
|
mob->setDirection(tile->direction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Direction::NegativeY: {
|
||||||
|
if (tile->direction == Direction::PositiveX) {
|
||||||
|
if (mob->getTileY() < mob->getTileX()) {
|
||||||
|
mob->setCenterY(tileY + mob->getTileX());
|
||||||
|
mob->setDirection(tile->direction);
|
||||||
|
}
|
||||||
|
} else { // tile->direction = Direction::NegativeX
|
||||||
|
if (mob->getTileY() < 1 - mob->getTileX()) {
|
||||||
|
mob->setCenterY(tileY + (1 - mob->getTileX()));
|
||||||
|
mob->setDirection(tile->direction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Direction::PositiveX: {
|
||||||
|
if (tile->direction == Direction::NegativeY) {
|
||||||
|
if (mob->getTileX() > mob->getTileY()) {
|
||||||
|
mob->setCenterX(tileX + mob->getTileY());
|
||||||
|
mob->setDirection(tile->direction);
|
||||||
|
}
|
||||||
|
} else { // tile->direction = Direction::PositiveY
|
||||||
|
if (mob->getTileX() > 1 - mob->getTileY()) {
|
||||||
|
mob->setCenterX(tileX + (1 - mob->getTileY()));
|
||||||
|
mob->setDirection(tile->direction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Direction::NegativeX: {
|
||||||
|
if (tile->direction == Direction::PositiveY) {
|
||||||
|
if (mob->getTileX() < mob->getTileY()) {
|
||||||
|
mob->setCenterX(tileX + mob->getTileY());
|
||||||
|
mob->setDirection(tile->direction);
|
||||||
|
}
|
||||||
|
} else { // tile->direction = Direction::NegativeY
|
||||||
|
if (mob->getTileX() < 1 - mob->getTileY()) {
|
||||||
|
mob->setCenterX(tileX + (1 - mob->getTileY()));
|
||||||
|
mob->setDirection(tile->direction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::moveMobs(std::uint64_t delta) {
|
||||||
|
for (MobPtr mob : m_Mobs) {
|
||||||
|
TilePtr tile = getTile(mob->getCenter().getX(), mob->getCenter().getY());
|
||||||
|
|
||||||
|
if (tile != nullptr && tile->getType() == TileType::Walk) {
|
||||||
|
WalkableTilePtr walkTile = std::static_pointer_cast<WalkableTile>(tile);
|
||||||
|
changeMobDirection(mob, walkTile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mob->hasReachedEnemyCastle()) continue;
|
||||||
|
|
||||||
|
moveMob(mob, delta);
|
||||||
|
|
||||||
|
TeamColor mobTeam = m_Game->getPlayerById(mob->getSender()).getTeamColor();
|
||||||
|
|
||||||
|
const TeamCastle* enemyCastle = nullptr;
|
||||||
|
|
||||||
|
if (mobTeam == TeamColor::Red) {
|
||||||
|
enemyCastle = &getBlueTeam().getCastle();
|
||||||
|
} else if (mobTeam == TeamColor::Blue) {
|
||||||
|
enemyCastle = &getRedTeam().getCastle();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMobTouchingCastle(mob, *enemyCastle)) {
|
||||||
|
moveBackMob(mob, *enemyCastle);
|
||||||
|
mob->setMobReachedCastle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::moveMob(MobPtr mob, std::uint64_t delta) {
|
||||||
float mobWalkSpeed = mob->getStats()->getMovementSpeed();
|
float mobWalkSpeed = mob->getStats()->getMovementSpeed();
|
||||||
|
|
||||||
float walkAmount = mobWalkSpeed * ((float)delta / 1000.0f);
|
float walkAmount = mobWalkSpeed * ((float)delta / 1000.0f);
|
||||||
|
|
||||||
if (mob->hasEffect(EffectType::Slowness))
|
if (mob->hasEffect(EffectType::Slowness))
|
||||||
walkAmount *= 0.70;
|
walkAmount *= 0.70; // walk 30% slower
|
||||||
|
|
||||||
switch (mob->getDirection()) {
|
switch (mob->getDirection()) {
|
||||||
case Direction::NegativeX: {
|
case Direction::NegativeX: {
|
||||||
mob->setX(mob->getX() - walkAmount);
|
mob->setCenterX(mob->getCenterX() - walkAmount);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Direction::PositiveX: {
|
case Direction::PositiveX: {
|
||||||
mob->setX(mob->getX() + walkAmount);
|
mob->setCenterX(mob->getCenterX() + walkAmount);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Direction::NegativeY: {
|
case Direction::NegativeY: {
|
||||||
mob->setY(mob->getY() - walkAmount);
|
mob->setCenterY(mob->getCenterY() - walkAmount);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Direction::PositiveY: {
|
case Direction::PositiveY: {
|
||||||
mob->setY(mob->getY() + walkAmount);
|
mob->setCenterY(mob->getCenterY() + walkAmount);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool World::isMobTouchingCastle(MobPtr mob, const TeamCastle& enemyCastle) const {
|
||||||
|
return enemyCastle.collidesWith(*mob);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::moveBackMob(MobPtr mob, const TeamCastle& enemyCastle) {
|
||||||
|
switch (mob->getDirection()) {
|
||||||
|
case Direction::NegativeX: {
|
||||||
|
mob->setCenterX(enemyCastle.getBottomRight().getX() + mob->getWidth() / 2.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Direction::PositiveX: {
|
||||||
|
mob->setCenterX(enemyCastle.getTopLeft().getX() - mob->getWidth() / 2.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Direction::NegativeY: {
|
||||||
|
mob->setCenterY(enemyCastle.getBottomRight().getY() + mob->getHeight() / 2.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Direction::PositiveY: {
|
||||||
|
mob->setCenterY(enemyCastle.getTopLeft().getY() - mob->getHeight() / 2.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Color* World::getTileColor(TilePtr tile) const {
|
const Color* World::getTileColor(TilePtr tile) const {
|
||||||
@@ -245,8 +361,7 @@ void World::cleanDeadMobs() {
|
|||||||
for (std::size_t i = 0; i < m_Mobs.size(); i++) {
|
for (std::size_t i = 0; i < m_Mobs.size(); i++) {
|
||||||
MobPtr mob = m_Mobs[i];
|
MobPtr mob = m_Mobs[i];
|
||||||
if (mob->isDead()) {
|
if (mob->isDead()) {
|
||||||
mob->OnDeath(this);
|
if (mob->OnDeath(this)) {
|
||||||
|
|
||||||
//reward players
|
//reward players
|
||||||
Player& sender = m_Game->getPlayerById(mob->getSender());
|
Player& sender = m_Game->getPlayerById(mob->getSender());
|
||||||
sender.addExp(mob->getStats()->getExpReward());
|
sender.addExp(mob->getStats()->getExpReward());
|
||||||
@@ -258,17 +373,18 @@ void World::cleanDeadMobs() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TowerPtr World::getTower(const glm::vec2& position) const {
|
TowerPtr World::getTower(const glm::vec2& position) const {
|
||||||
for (TowerPtr tower : m_Towers) {
|
for (TowerPtr tower : m_Towers) {
|
||||||
if (tower->getSize() == TowerSize::Big) {
|
if (tower->getSize() == TowerSize::Big) {
|
||||||
if (tower->getX() - 2 <= static_cast<std::int32_t>(position.x) && tower->getX() + 2 >= static_cast<std::int32_t>(position.x) &&
|
if (tower->getCenterX() - 2.5f < position.x && tower->getCenterX() + 2.5f > position.x &&
|
||||||
tower->getY() - 2 <= static_cast<std::int32_t>(position.y) && tower->getY() + 2 >= static_cast<std::int32_t>(position.y)) {
|
tower->getCenterY() - 2.5f < position.y && tower->getCenterY() + 2.5f > position.y) {
|
||||||
return tower;
|
return tower;
|
||||||
}
|
}
|
||||||
} else {
|
} else { // little tower
|
||||||
if (tower->getX() - 1 <= static_cast<std::int32_t>(position.x) && tower->getX() + 1 >= static_cast<std::int32_t>(position.x) &&
|
if (tower->getCenterX() - 1.5f < position.x && tower->getCenterX() + 1.5f > position.x &&
|
||||||
tower->getY() - 1 <= static_cast<std::int32_t>(position.y) && tower->getY() + 1 >= static_cast<std::int32_t>(position.y)) {
|
tower->getCenterY() - 1.5f < position.y && tower->getCenterY() + 1.5f > position.y) {
|
||||||
return tower;
|
return tower;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,12 +398,32 @@ TowerPtr World::getTowerById(TowerID towerID) {
|
|||||||
return *it;
|
return *it;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::OnArrowShot(MobPtr target, Tower* shooter) {
|
void World::OnArcherTowerShot(MobPtr target, ArcherTower* shooter) {
|
||||||
bool explosiveArrows = shooter->getLevel().getPath() == TowerPath::Bottom;
|
bool explosiveArrows = shooter->getLevel().getPath() == TowerPath::Bottom;
|
||||||
|
notifyListeners(&WorldListener::OnArrowShot, target, shooter);
|
||||||
if (explosiveArrows) {
|
if (explosiveArrows) {
|
||||||
// aoe damage
|
notifyListeners(&WorldListener::OnExplosion, utils::shape::Circle{ target->getCenterX(), target->getCenterY(), ArcherTower::ExplosionRadius }, shooter->getStats()->getDamage(), shooter);
|
||||||
} else {
|
}
|
||||||
target->damage(shooter->getStats()->getDamage(), shooter);
|
}
|
||||||
|
|
||||||
|
void World::OnArrowShot(MobPtr target, Tower* shooter) {
|
||||||
|
notifyListeners(&WorldListener::OnMobDamage, target, shooter->getStats()->getDamage(), shooter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) {
|
||||||
|
for (MobPtr mob : m_Mobs) {
|
||||||
|
if (mob->isAlive() && mob->collidesWith(explosion)) {
|
||||||
|
// linear distance damage reduction
|
||||||
|
float explosionDamage = mob->distance(explosion) / explosion.getRadius() * centerDamage;
|
||||||
|
notifyListeners(&WorldListener::OnMobDamage, mob, explosionDamage, shooter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::OnMobDamage(MobPtr target, float damage, Tower* source) {
|
||||||
|
target->damage(damage, source);
|
||||||
|
if (target->isDead()) {
|
||||||
|
notifyListeners(&WorldListener::OnMobDead, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ void ClientGame::HandlePacket(const protocol::WorldDataPacket* packet) {
|
|||||||
m_WorldRenderer.loadModels();
|
m_WorldRenderer.loadModels();
|
||||||
// set cam pos to player spawn
|
// set cam pos to player spawn
|
||||||
const game::Spawn& spawn = m_World->getTeam(m_Player->getTeamColor()).getSpawn();
|
const game::Spawn& spawn = m_World->getTeam(m_Player->getTeamColor()).getSpawn();
|
||||||
m_WorldRenderer.setCamPos(spawn.x + 0.5, spawn.y + 0.5);
|
m_WorldRenderer.setCamPos(spawn.getCenterX(), spawn.getCenterY());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientGame::renderWorld() {
|
void ClientGame::renderWorld() {
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ void ServerWorld::spawnMobs(game::MobType type, std::uint8_t level, game::Player
|
|||||||
enemyMobSpawn = &getTeam(game::TeamColor::Red).getSpawn();
|
enemyMobSpawn = &getTeam(game::TeamColor::Red).getSpawn();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::int32_t spawnCenterX = enemyMobSpawn->x;
|
std::int32_t spawnCenterX = enemyMobSpawn->getCenterX();
|
||||||
std::int32_t spawnCenterY = enemyMobSpawn->y;
|
std::int32_t spawnCenterY = enemyMobSpawn->getCenterY();
|
||||||
|
|
||||||
std::int32_t minSpawnY = spawnCenterY - 2;
|
std::int32_t minSpawnY = spawnCenterY - 2;
|
||||||
std::int32_t maxSpawnY = spawnCenterY + 2;
|
std::int32_t maxSpawnY = spawnCenterY + 2;
|
||||||
@@ -34,9 +34,9 @@ void ServerWorld::spawnMobs(game::MobType type, std::uint8_t level, game::Player
|
|||||||
float mobX = utils::getRandomReal<float>(minSpawnX, maxSpawnX);
|
float mobX = utils::getRandomReal<float>(minSpawnX, maxSpawnX);
|
||||||
float mobY = utils::getRandomReal<float>(minSpawnY, maxSpawnY);
|
float mobY = utils::getRandomReal<float>(minSpawnY, maxSpawnY);
|
||||||
|
|
||||||
spawnMobAt(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->direction);
|
spawnMobAt(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->getDirection());
|
||||||
|
|
||||||
protocol::SpawnMobPacket packet(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->direction);
|
protocol::SpawnMobPacket packet(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->getDirection());
|
||||||
m_Server->broadcastPacket(&packet);
|
m_Server->broadcastPacket(&packet);
|
||||||
|
|
||||||
m_CurrentMobID++;
|
m_CurrentMobID++;
|
||||||
|
|||||||
84
src/misc/Shapes.cpp
Normal file
84
src/misc/Shapes.cpp
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
#include "misc/Shapes.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace utils {
|
||||||
|
namespace shape {
|
||||||
|
|
||||||
|
float Point::distance(const Point& point) const {
|
||||||
|
return std::sqrt(distanceSquared(point));
|
||||||
|
}
|
||||||
|
|
||||||
|
float Point::distanceSquared(const Point& point) const {
|
||||||
|
return (m_X - point.getX()) * (m_X - point.getX()) + (m_Y - point.getY()) * (m_Y - point.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Rectangle::collidesWith(const Point& point) const {
|
||||||
|
return point.getX() > getTopLeft().getX() && point.getX() < getBottomRight().getX() &&
|
||||||
|
point.getY() > getTopLeft().getY() && point.getY() < getBottomRight().getY();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rectangle::collidesWith(const Rectangle& rect) const {
|
||||||
|
Point point1{ rect.getTopLeft().getX(), rect.getTopLeft().getY() };
|
||||||
|
Point point2{ rect.getTopLeft().getX(), rect.getBottomRight().getY() };
|
||||||
|
Point point3{ rect.getBottomRight().getX(), rect.getTopLeft().getY() };
|
||||||
|
Point point4{ rect.getBottomRight().getX(), rect.getBottomRight().getY() };
|
||||||
|
|
||||||
|
if (collidesWith(point1)) return true;
|
||||||
|
if (collidesWith(point2)) return true;
|
||||||
|
if (collidesWith(point3)) return true;
|
||||||
|
if (collidesWith(point4)) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rectangle::collidesWith(const Circle& circle) const {
|
||||||
|
return circle.collidesWith(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Rectangle::distance(const Circle& circle) const {
|
||||||
|
return circle.distance(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Rectangle::distanceSquared(const Circle& circle) const {
|
||||||
|
return circle.distanceSquared(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool Circle::collidesWith(const Point& point) const {
|
||||||
|
return m_Radius * m_Radius > m_Center.distanceSquared(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Circle::collidesWith(const Rectangle& rect) const {
|
||||||
|
float distanceSquared_ = distanceSquared(rect);
|
||||||
|
|
||||||
|
return distanceSquared_ < m_Radius* m_Radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Circle::collidesWith(const Circle& circle) const {
|
||||||
|
return m_Radius + circle.getRadius() > m_Center.distanceSquared(circle.getCenter());
|
||||||
|
}
|
||||||
|
|
||||||
|
float Circle::distance(const Rectangle& rect) const {
|
||||||
|
return std::sqrt(distanceSquared(rect));
|
||||||
|
}
|
||||||
|
|
||||||
|
float Circle::distanceSquared(const Rectangle& rect) const {
|
||||||
|
float closestX = std::clamp(m_Center.getX(), rect.getTopLeft().getX(), rect.getBottomRight().getX());
|
||||||
|
float closestY = std::clamp(m_Center.getY(), rect.getTopLeft().getY(), rect.getBottomRight().getY());
|
||||||
|
|
||||||
|
float distanceX = m_Center.getX() - closestX;
|
||||||
|
float distanceY = m_Center.getY() - closestY;
|
||||||
|
|
||||||
|
return (distanceX * distanceX) + (distanceY * distanceY);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace shape
|
||||||
|
} // namespace utils
|
||||||
|
} // namespace td
|
||||||
@@ -74,7 +74,7 @@ void WorldRenderer::renderMobs() const {
|
|||||||
for (game::MobPtr mob : m_World->getMobList()) {
|
for (game::MobPtr mob : m_World->getMobList()) {
|
||||||
Renderer::Model model;
|
Renderer::Model model;
|
||||||
model.vao = m_MobVao.get();
|
model.vao = m_MobVao.get();
|
||||||
model.positon = { mob->getX(), mob->getY() };
|
model.positon = { mob->getCenterX(), mob->getCenterY() };
|
||||||
m_Renderer->renderModel(model);
|
m_Renderer->renderModel(model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,11 +235,7 @@ void WorldRenderer::renderMobTooltip() const {
|
|||||||
void WorldRenderer::detectMobHovering() const {
|
void WorldRenderer::detectMobHovering() const {
|
||||||
glm::vec2 cursorWorldPos = getCursorWorldPos();
|
glm::vec2 cursorWorldPos = getCursorWorldPos();
|
||||||
for (game::MobPtr mob : m_World->getMobList()) {
|
for (game::MobPtr mob : m_World->getMobList()) {
|
||||||
// mob size is currently 1x1 for all mobs
|
if(mob->collidesWith({cursorWorldPos.x, cursorWorldPos.y})){
|
||||||
float mobCenterX = mob->getX();
|
|
||||||
float mobCenterY = mob->getY();
|
|
||||||
if (cursorWorldPos.x > mobCenterX - 0.5f && cursorWorldPos.x < mobCenterX + 0.5f
|
|
||||||
&& cursorWorldPos.y > mobCenterY - 0.5f && cursorWorldPos.y < mobCenterY + 0.5f) {
|
|
||||||
m_MobTooltip->setMob(mob.get());
|
m_MobTooltip->setMob(mob.get());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,8 +97,8 @@ GL::VertexArray loadWorldModel(const td::game::World* world) {
|
|||||||
|
|
||||||
for (int spawnColor = 0; spawnColor < 2; spawnColor++) {
|
for (int spawnColor = 0; spawnColor < 2; spawnColor++) {
|
||||||
const game::Spawn& spawn = world->getTeam(game::TeamColor(spawnColor)).getSpawn();
|
const game::Spawn& spawn = world->getTeam(game::TeamColor(spawnColor)).getSpawn();
|
||||||
float fromX = spawn.x - 2, toX = spawn.x + 3;
|
float fromX = spawn.getTopLeft().getX() , toX = spawn.getBottomRight().getX();
|
||||||
float fromY = spawn.y - 2, toY = spawn.y + 3;
|
float fromY = spawn.getTopLeft().getY() , toY = spawn.getBottomRight().getY();
|
||||||
|
|
||||||
positions.insert(positions.end(), {
|
positions.insert(positions.end(), {
|
||||||
fromX, fromY,
|
fromX, fromY,
|
||||||
@@ -125,8 +125,8 @@ GL::VertexArray loadWorldModel(const td::game::World* world) {
|
|||||||
|
|
||||||
for (int castleColor = 0; castleColor < 2; castleColor++) {
|
for (int castleColor = 0; castleColor < 2; castleColor++) {
|
||||||
const game::TeamCastle& castle = world->getTeam(game::TeamColor(castleColor)).getCastle();
|
const game::TeamCastle& castle = world->getTeam(game::TeamColor(castleColor)).getCastle();
|
||||||
float fromX = castle.x - 2, toX = castle.x + 3;
|
float fromX = castle.getTopLeft().getX(), toX = castle.getBottomRight().getX();
|
||||||
float fromY = castle.y - 2, toY = castle.y + 3;
|
float fromY = castle.getTopLeft().getY(), toY = castle.getBottomRight().getY();
|
||||||
|
|
||||||
positions.insert(positions.end(), {
|
positions.insert(positions.end(), {
|
||||||
fromX, fromY,
|
fromX, fromY,
|
||||||
@@ -203,17 +203,17 @@ RenderData loadTowerModel(game::TowerPtr tower) {
|
|||||||
float towerY, towerDY;
|
float towerY, towerDY;
|
||||||
|
|
||||||
if (tower->getSize() == game::TowerSize::Little) {
|
if (tower->getSize() == game::TowerSize::Little) {
|
||||||
towerX = tower->getX() - 1;
|
towerX = tower->getCenterX() - 1.5f;
|
||||||
towerDX = tower->getX() + 2;
|
towerDX = tower->getCenterX() + 1.5f;
|
||||||
|
|
||||||
towerY = tower->getY() - 1;
|
towerY = tower->getCenterY() - 1.5f;
|
||||||
towerDY = tower->getY() + 2;
|
towerDY = tower->getCenterY() + 1.5f;
|
||||||
} else {
|
} else {
|
||||||
towerX = tower->getX() - 2;
|
towerX = tower->getCenterX() - 2.5f;
|
||||||
towerDX = tower->getX() + 3;
|
towerDX = tower->getCenterX() + 2.5f;
|
||||||
|
|
||||||
towerY = tower->getY() - 2;
|
towerY = tower->getCenterY() - 2.5f;
|
||||||
towerDY = tower->getY() + 3;
|
towerDY = tower->getCenterY() + 2.5f;
|
||||||
}
|
}
|
||||||
std::vector<float> positions = {
|
std::vector<float> positions = {
|
||||||
towerX, towerY,
|
towerX, towerY,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "misc/Updater.h"
|
#include "updater/Updater.h"
|
||||||
|
|
||||||
#include "misc/Platform.h"
|
#include "misc/Platform.h"
|
||||||
#include "misc/DataBuffer.h"
|
#include "misc/DataBuffer.h"
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ target("TowerDefense")
|
|||||||
add_files("src/*.cpp", "src/*/*.cpp", "src/*/*/*.cpp", "src/*/*/*/*.cpp")
|
add_files("src/*.cpp", "src/*/*.cpp", "src/*/*/*.cpp", "src/*/*/*/*.cpp")
|
||||||
add_cxflags("-pthread")
|
add_cxflags("-pthread")
|
||||||
|
|
||||||
set_languages("c++14")
|
set_languages("c++17")
|
||||||
|
|
||||||
add_links("glbinding", "z", "SDL2")
|
add_links("glbinding", "z", "SDL2")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user