Compare commits
25 Commits
alpha-0.0.
...
alpha-0.0.
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e91b863da | |||
| 129bb47286 | |||
| e4a9c5f763 | |||
| 78cf2d0f18 | |||
| 00d2b5394f | |||
| 00414abe61 | |||
| cb847d0edd | |||
| 2da0bd9b79 | |||
| cf9633c061 | |||
| 7a6fdc30b6 | |||
| 657fe761ab | |||
| 687944bf51 | |||
| 93e079ddb3 | |||
| 8171a91ed5 | |||
| 0c1824e40b | |||
| f91ab4bc83 | |||
| 1843fc6f4d | |||
| 6a51638b7e | |||
| 8351c5d09f | |||
| ee94c811e1 | |||
| 50a8269773 | |||
| 2996c88d94 | |||
| 55263fa582 | |||
| adeddee09d | |||
| f0115166c0 |
@@ -86,6 +86,7 @@ private:
|
||||
Direction m_Direction;
|
||||
std::vector<EffectDuration> m_Effects;
|
||||
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_EffectPoisonTimer;
|
||||
@@ -93,7 +94,8 @@ private:
|
||||
|
||||
public:
|
||||
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) {
|
||||
|
||||
}
|
||||
|
||||
@@ -112,9 +114,11 @@ public:
|
||||
bool isDead() const { return m_Health <= 0; }
|
||||
bool isAlive() const { return m_Health > 0; }
|
||||
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 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
|
||||
|
||||
bool isImmuneTo(TowerType type);
|
||||
|
||||
@@ -122,6 +126,8 @@ public:
|
||||
void addEffect(EffectType type, float durationSec, const Tower* tower);
|
||||
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; }
|
||||
void setDirection(Direction dir) { m_Direction = dir; }
|
||||
|
||||
@@ -163,6 +163,9 @@ class ArcherTower : public LittleTower {
|
||||
public:
|
||||
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;
|
||||
constexpr static float FireDurationSec = 10.0f;
|
||||
|
||||
virtual TowerType getType() const { return TowerType::Archer; }
|
||||
virtual void tick(std::uint64_t delta, World* world);
|
||||
};
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "Mobs.h"
|
||||
#include "Team.h"
|
||||
|
||||
#include "misc/ObjectNotifier.h"
|
||||
|
||||
namespace td {
|
||||
namespace game {
|
||||
typedef std::pair<std::int16_t, std::int16_t> ChunkCoord;
|
||||
@@ -114,7 +116,26 @@ typedef std::array<Color, 2> SpawnColorPalette;
|
||||
|
||||
typedef std::vector<TowerPtr> TowerList;
|
||||
|
||||
class World {
|
||||
class WorldListener {
|
||||
public:
|
||||
WorldListener() {}
|
||||
|
||||
virtual void OnTowerAdd(TowerPtr tower) {}
|
||||
virtual void OnTowerRemove(TowerPtr tower) {}
|
||||
|
||||
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter) {}
|
||||
|
||||
virtual void OnArrowShot(MobPtr target, bool fire, 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:
|
||||
TowerTileColorPalette m_TowerPlacePalette;
|
||||
Color m_WalkablePalette;
|
||||
@@ -147,6 +168,7 @@ public:
|
||||
void spawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir);
|
||||
|
||||
TowerPtr placeTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder);
|
||||
TowerPtr removeTower(TowerID id);
|
||||
|
||||
TilePtr getTile(std::int32_t x, std::int32_t y) const;
|
||||
|
||||
@@ -189,12 +211,19 @@ public:
|
||||
const TowerList& getTowers() const { return m_Towers; };
|
||||
TowerPtr getTowerById(TowerID tower);
|
||||
|
||||
// Archer Tower
|
||||
virtual void OnArrowShot(MobPtr target, Tower* shooter);
|
||||
// WorldListener
|
||||
|
||||
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter);
|
||||
|
||||
virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter);
|
||||
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter);
|
||||
|
||||
virtual void OnMobDamage(MobPtr target, float damage, Tower* source);
|
||||
private:
|
||||
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 cleanDeadMobs();
|
||||
|
||||
@@ -44,6 +44,7 @@ public:
|
||||
void sendMobs(const std::vector<protocol::MobSend>& mobSends);
|
||||
void placeTower(game::TowerType type, const glm::vec2& position);
|
||||
void upgradeTower(game::TowerID tower, game::TowerLevel level);
|
||||
void removeTower(game::TowerID tower);
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
@@ -37,6 +37,7 @@ public:
|
||||
Client* getClient() const { return m_Client; }
|
||||
|
||||
render::Renderer* getRenderer() const { return m_Renderer; }
|
||||
WorldClient& getWorld() { return m_WorldClient; }
|
||||
|
||||
virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet);
|
||||
virtual void HandlePacket(const protocol::PlayerJoinPacket* packet);
|
||||
@@ -48,7 +49,7 @@ public:
|
||||
virtual void HandlePacket(const protocol::UpdateMoneyPacket* packet);
|
||||
virtual void HandlePacket(const protocol::DisconnectPacket* packet);
|
||||
virtual void HandlePacket(const protocol::WorldDataPacket* packet);
|
||||
virtual void HandlePacket(const protocol::WorldAddTowerPacket* packet);
|
||||
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
@@ -14,12 +14,13 @@ private:
|
||||
public:
|
||||
WorldClient(ClientGame* game);
|
||||
|
||||
virtual void HandlePacket(const protocol::WorldBeginDataPacket* packet) override;
|
||||
virtual void HandlePacket(const protocol::WorldDataPacket* packet) override;
|
||||
virtual void HandlePacket(const protocol::SpawnMobPacket* packet) override;
|
||||
virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet) override;
|
||||
virtual void HandlePacket(const protocol::WorldBeginDataPacket* packet);
|
||||
virtual void HandlePacket(const protocol::WorldDataPacket* packet);
|
||||
virtual void HandlePacket(const protocol::SpawnMobPacket* packet);
|
||||
virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet);
|
||||
virtual void HandlePacket(const protocol::WorldAddTowerPacket* packet);
|
||||
virtual void HandlePacket(const protocol::RemoveTowerPacket* packet);
|
||||
|
||||
virtual void OnArrowShot(game::MobPtr target, game::Tower* shooter) override;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
@@ -40,6 +40,7 @@ public:
|
||||
virtual void HandlePacket(const protocol::PlaceTowerPacket* packet);
|
||||
virtual void HandlePacket(const protocol::SendMobsPacket* packet);
|
||||
virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet);
|
||||
virtual void HandlePacket(const protocol::RemoveTowerPacket* packet);
|
||||
|
||||
std::uint8_t getID() const { return m_ID; }
|
||||
const game::Player* getPlayer() const { return m_Player; }
|
||||
|
||||
@@ -19,7 +19,6 @@ public:
|
||||
void spawnMobs(game::MobType type, std::uint8_t level, game::PlayerID sender, std::uint8_t count);
|
||||
game::TowerPtr placeTowerAt(game::TowerType type, std::int32_t x, std::int32_t y, game::PlayerID builder);
|
||||
|
||||
virtual void OnArrowShot(game::MobPtr target, game::Tower* shooter) override;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
|
||||
4465
include/misc/Backward.hpp
Normal file
4465
include/misc/Backward.hpp
Normal file
File diff suppressed because it is too large
Load Diff
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
|
||||
@@ -53,6 +53,10 @@ public:
|
||||
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 {
|
||||
@@ -78,6 +82,10 @@ public:
|
||||
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
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
// utililty class to call function at regular period of time
|
||||
class Timer {
|
||||
private:
|
||||
std::uint64_t m_Interval;
|
||||
std::uint64_t m_Interval; // in millis
|
||||
std::uint64_t m_InternalTime = 0;
|
||||
public:
|
||||
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)
|
||||
class CooldownTimer {
|
||||
private:
|
||||
std::uint64_t m_Cooldown;
|
||||
std::uint64_t m_Cooldown; // in millis
|
||||
std::uint64_t m_CooldownTime;
|
||||
public:
|
||||
CooldownTimer() : m_Cooldown(0), m_CooldownTime(0) {}
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
virtual void HandlePacket(const SpawnMobPacket* packet) {}
|
||||
virtual void HandlePacket(const PlaceTowerPacket* packet) {}
|
||||
virtual void HandlePacket(const WorldAddTowerPacket* packet) {}
|
||||
virtual void HandlePacket(const WorldRemoveTowerPacket* packet) {}
|
||||
virtual void HandlePacket(const RemoveTowerPacket* packet) {}
|
||||
virtual void HandlePacket(const SendMobsPacket* packet) {}
|
||||
virtual void HandlePacket(const UpgradeTowerPacket* packet) {}
|
||||
};
|
||||
|
||||
@@ -33,12 +33,12 @@ enum class PacketType : std::uint8_t {
|
||||
UpdatePlayerTeam,
|
||||
ServerTps,
|
||||
WorldAddTower,
|
||||
WorldRemoveTower,
|
||||
|
||||
// client <--> server
|
||||
KeepAlive,
|
||||
Disconnect,
|
||||
UpgradeTower,
|
||||
RemoveTower,
|
||||
};
|
||||
|
||||
struct WorldHeader {
|
||||
@@ -477,13 +477,13 @@ public:
|
||||
virtual PacketType getType() const { return PacketType::WorldAddTower; }
|
||||
};
|
||||
|
||||
class WorldRemoveTowerPacket : public Packet {
|
||||
class RemoveTowerPacket : public Packet {
|
||||
private:
|
||||
game::TowerID m_TowerID;
|
||||
public:
|
||||
WorldRemoveTowerPacket() {}
|
||||
WorldRemoveTowerPacket(game::TowerID id) : m_TowerID(id) {}
|
||||
virtual ~WorldRemoveTowerPacket() {}
|
||||
RemoveTowerPacket() {}
|
||||
RemoveTowerPacket(game::TowerID id) : m_TowerID(id) {}
|
||||
virtual ~RemoveTowerPacket() {}
|
||||
|
||||
virtual DataBuffer Serialize() const;
|
||||
virtual void Deserialize(DataBuffer& data);
|
||||
@@ -491,7 +491,7 @@ public:
|
||||
|
||||
game::TowerID getTowerID() const { return m_TowerID; }
|
||||
|
||||
virtual PacketType getType() const { return PacketType::WorldRemoveTower; }
|
||||
virtual PacketType getType() const { return PacketType::RemoveTower; }
|
||||
};
|
||||
|
||||
class UpgradeTowerPacket : public Packet {
|
||||
|
||||
@@ -12,15 +12,19 @@ namespace render {
|
||||
class VertexCache {
|
||||
|
||||
typedef std::vector<float> Vector;
|
||||
typedef std::pair<Vector::iterator, Vector::iterator> ElementsIndex;
|
||||
typedef std::pair<ElementsIndex, ElementsIndex> DataIndex;
|
||||
|
||||
struct DataIndex {
|
||||
Vector position;
|
||||
Vector color;
|
||||
};
|
||||
|
||||
private:
|
||||
Vector m_Positions;
|
||||
Vector m_Colors;
|
||||
std::size_t m_VertexCount;
|
||||
std::unordered_map<std::uint64_t, DataIndex> m_Indexes;
|
||||
std::unique_ptr<GL::VertexArray> m_VertexArray;
|
||||
public:
|
||||
VertexCache() : m_VertexCount(0) {}
|
||||
|
||||
void addData(std::uint64_t index, std::vector<float> positions, std::vector<float> colors);
|
||||
void removeData(std::uint64_t index);
|
||||
void clear();
|
||||
|
||||
@@ -23,7 +23,7 @@ class ClientGame;
|
||||
|
||||
namespace render {
|
||||
|
||||
class WorldRenderer {
|
||||
class WorldRenderer : public game::WorldListener {
|
||||
private:
|
||||
client::ClientGame* m_Client;
|
||||
Renderer* m_Renderer;
|
||||
@@ -46,9 +46,6 @@ public:
|
||||
|
||||
void loadModels();
|
||||
|
||||
void addTower(game::TowerPtr tower);
|
||||
void removeTower(game::TowerPtr tower);
|
||||
|
||||
static ImVec4 getImGuiTeamColor(game::TeamColor color);
|
||||
|
||||
void update();
|
||||
@@ -58,6 +55,11 @@ public:
|
||||
|
||||
void moveCam(float relativeX, float relativeY, float aspectRatio);
|
||||
void changeZoom(float zoom);
|
||||
|
||||
// WorldListener
|
||||
|
||||
virtual void OnTowerAdd(game::TowerPtr tower);
|
||||
virtual void OnTowerRemove(game::TowerPtr tower);
|
||||
private:
|
||||
void click();
|
||||
void renderWorld() const;
|
||||
@@ -69,6 +71,7 @@ private:
|
||||
void renderMobTooltip() const;
|
||||
void detectClick();
|
||||
void detectMobHovering() const;
|
||||
void removeTower();
|
||||
glm::vec2 getCursorWorldPos() const;
|
||||
glm::vec2 getClickWorldPos() const;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "GuiWidget.h"
|
||||
|
||||
#include "misc/Updater.h"
|
||||
#include "updater/Updater.h"
|
||||
|
||||
#include <future>
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "DataBuffer.h"
|
||||
#include "misc/DataBuffer.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#define TD_VERSION "alpha-0.0.2"
|
||||
#define TD_VERSION "alpha-0.0.4"
|
||||
|
||||
namespace td {
|
||||
namespace utils {
|
||||
@@ -6,14 +6,24 @@
|
||||
// Description : Hello World in C++, Ansi-style
|
||||
//============================================================================
|
||||
|
||||
#if !defined(NDEBUG) && !defined(_WIN32)
|
||||
#define BACKWARD_HAS_UNWIND 1
|
||||
#define BACKWARD_HAS_DW 1
|
||||
#endif
|
||||
|
||||
#include "window/Display.h"
|
||||
#include "misc/Updater.h"
|
||||
#include "updater/Updater.h"
|
||||
#include "misc/Backward.hpp"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
extern "C"
|
||||
#endif
|
||||
|
||||
int main(int argc, const char* args[]) {
|
||||
// setup signal handling
|
||||
backward::SignalHandling sh;
|
||||
|
||||
// remove the outdated binary
|
||||
td::utils::Updater::removeOldFile();
|
||||
|
||||
Display::create();
|
||||
|
||||
@@ -235,7 +235,7 @@ const std::map<MobKey, EffectImmunities> MobsEffectImmunities = {
|
||||
|
||||
{{MobType::Skeleton, 1},{}},
|
||||
{{MobType::Skeleton, 2},{}},
|
||||
{{MobType::Skeleton, 3},{EffectType::Fire}},
|
||||
{{MobType::Skeleton, 3},{}},
|
||||
{{MobType::Skeleton, 4},{EffectType::Fire}},
|
||||
{{MobType::Skeleton, 5},{EffectType::Fire}},
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ const std::map<std::pair<TowerType, TowerLevel>, TowerStats> TowerConstants = {
|
||||
{{TowerType::Archer, {4, TowerPath::Top}}, {0.8, 0, 15}},
|
||||
|
||||
{{TowerType::Archer, {2, TowerPath::Bottom}}, {2, 10, 12}},
|
||||
{{TowerType::Archer, {3, TowerPath::Bottom}}, {2, 0, 13}},
|
||||
{{TowerType::Archer, {4, TowerPath::Bottom}}, {2, 0, 15}},
|
||||
{{TowerType::Archer, {3, TowerPath::Bottom}}, {2, 10, 13}},
|
||||
{{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();
|
||||
for (MobPtr mob : world->getMobList()) {
|
||||
if (isMobInRange(mob)) {
|
||||
world->OnArrowShot(mob, this);
|
||||
world->notifyListeners(&WorldListener::OnArcherTowerShot, mob, this);
|
||||
m_Timer.applyCooldown();
|
||||
arrowsShot++;
|
||||
if (arrowsShot >= arrows)
|
||||
break;
|
||||
m_Timer.applyCooldown();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,7 +229,8 @@ void IceTower::tick(std::uint64_t delta, World* world) {
|
||||
for (MobPtr mob : world->getMobList()) {
|
||||
if (isMobInRange(mob)) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -252,7 +253,7 @@ void PoisonTower::tick(std::uint64_t delta, World* world) {
|
||||
for (MobPtr mob : world->getMobList()) {
|
||||
if (isMobInRange(mob)) {
|
||||
if (getLevel().getPath() == TowerPath::Bottom) {
|
||||
mob->damage(getStats()->getDamage(), this);
|
||||
world->notifyListeners(&WorldListener::OnMobDamage, mob, getStats()->getDamage(), this);
|
||||
} else {
|
||||
float durationSec;
|
||||
switch (getLevel().getLevel()) {
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace td {
|
||||
namespace game {
|
||||
|
||||
World::World(Game* game) : m_Game(game) {
|
||||
|
||||
bindListener(this);
|
||||
}
|
||||
|
||||
TilePtr World::getTile(std::int32_t x, std::int32_t y) const {
|
||||
@@ -122,26 +122,110 @@ TowerPtr World::placeTowerAt(TowerID id, TowerType type, std::int32_t x, std::in
|
||||
return tower;
|
||||
}
|
||||
|
||||
TowerPtr World::removeTower(TowerID towerId) {
|
||||
auto it = std::find_if(m_Towers.begin(), m_Towers.end(), [towerId](TowerPtr tower) { return tower->getID() == towerId;});
|
||||
if (it == m_Towers.end()) return nullptr;
|
||||
|
||||
TowerPtr tower = *it;
|
||||
|
||||
m_Towers.erase(it);
|
||||
|
||||
return tower;
|
||||
}
|
||||
|
||||
void World::tickMobs(std::uint64_t delta) {
|
||||
for (MobPtr mob : m_Mobs) {
|
||||
mob->tick(delta);
|
||||
}
|
||||
}
|
||||
|
||||
void World::changeMobDirection(MobPtr mob, WalkableTilePtr tile) {
|
||||
if (mob->getDirection() == tile->direction) return;
|
||||
|
||||
float tileX = static_cast<float>(static_cast<std::int32_t>(mob->getCenterX()));
|
||||
float tileY = static_cast<float>(static_cast<std::int32_t>(mob->getCenterY()));
|
||||
|
||||
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) {
|
||||
WalkableTile* walkTile = dynamic_cast<WalkableTile*>(tile.get());
|
||||
mob->setDirection(walkTile->direction);
|
||||
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;
|
||||
const TeamCastle* enemyCastle = nullptr;
|
||||
|
||||
if (mobTeam == TeamColor::Red) {
|
||||
enemyCastle = &getBlueTeam().getCastle();
|
||||
@@ -151,6 +235,7 @@ void World::moveMobs(std::uint64_t delta) {
|
||||
|
||||
if (isMobTouchingCastle(mob, *enemyCastle)) {
|
||||
moveBackMob(mob, *enemyCastle);
|
||||
mob->setMobReachedCastle();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -324,12 +409,37 @@ TowerPtr World::getTowerById(TowerID towerID) {
|
||||
return *it;
|
||||
}
|
||||
|
||||
void World::OnArrowShot(MobPtr target, Tower* shooter) {
|
||||
bool explosiveArrows = shooter->getLevel().getPath() == TowerPath::Bottom;
|
||||
void World::OnArcherTowerShot(MobPtr target, ArcherTower* shooter) {
|
||||
bool fireArrows = shooter->getLevel().getPath() == TowerPath::Bottom;
|
||||
bool explosiveArrows = shooter->getLevel().getLevel() == 4 && fireArrows;
|
||||
|
||||
notifyListeners(&WorldListener::OnArrowShot, target, fireArrows, shooter);
|
||||
if (explosiveArrows) {
|
||||
// aoe damage
|
||||
} else {
|
||||
target->damage(shooter->getStats()->getDamage(), shooter);
|
||||
notifyListeners(&WorldListener::OnExplosion, utils::shape::Circle{ target->getCenterX(), target->getCenterY(), ArcherTower::ExplosionRadius }, shooter->getStats()->getDamage(), shooter);
|
||||
}
|
||||
}
|
||||
|
||||
void World::OnArrowShot(MobPtr target, bool fireArrow, Tower* shooter) {
|
||||
notifyListeners(&WorldListener::OnMobDamage, target, shooter->getStats()->getDamage(), shooter);
|
||||
if (fireArrow) {
|
||||
target->addEffect(EffectType::Fire, ArcherTower::FireDurationSec, 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,5 +64,10 @@ void Client::upgradeTower(game::TowerID tower, game::TowerLevel level) {
|
||||
m_Connexion.sendPacket(&packet);
|
||||
}
|
||||
|
||||
void Client::removeTower(game::TowerID tower) {
|
||||
protocol::RemoveTowerPacket packet(tower);
|
||||
m_Connexion.sendPacket(&packet);
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace td
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
#include "game/client/ClientGame.h"
|
||||
#include "protocol/PacketDispatcher.h"
|
||||
//#include "game/Team.h"
|
||||
#include "game/client/Client.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace td {
|
||||
namespace client {
|
||||
|
||||
@@ -21,7 +18,6 @@ m_WorldRenderer(&m_WorldClient, this) {
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMoney, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldAddTower, this);
|
||||
}
|
||||
|
||||
ClientGame::~ClientGame() {
|
||||
@@ -112,9 +108,5 @@ void ClientGame::renderWorld() {
|
||||
}
|
||||
}
|
||||
|
||||
void ClientGame::HandlePacket(const protocol::WorldAddTowerPacket* packet) {
|
||||
m_WorldRenderer.addTower(m_WorldClient.placeTowerAt(packet->getTowerID(), packet->getTowerType(), packet->getTowerX(), packet->getTowerY(), packet->getBuilder()));
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace td
|
||||
|
||||
@@ -7,10 +7,12 @@ namespace td {
|
||||
namespace client {
|
||||
|
||||
WorldClient::WorldClient(ClientGame* game) : game::World(game), protocol::PacketHandler(game->GetDispatcher()), m_Game(game) {
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldAddTower, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldBeginData, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::SpawnMob, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this);
|
||||
}
|
||||
|
||||
void WorldClient::HandlePacket(const protocol::WorldBeginDataPacket* packet) {
|
||||
@@ -32,8 +34,18 @@ void WorldClient::HandlePacket(const protocol::UpgradeTowerPacket* packet) {
|
||||
tower->upgrade(packet->getTowerLevel().getLevel(), packet->getTowerLevel().getPath());
|
||||
}
|
||||
|
||||
void WorldClient::OnArrowShot(game::MobPtr target, game::Tower* tower) {
|
||||
World::OnArrowShot(target, tower);
|
||||
void WorldClient::HandlePacket(const protocol::WorldAddTowerPacket* packet) {
|
||||
game::TowerPtr newTower = placeTowerAt(packet->getTowerID(), packet->getTowerType(), packet->getTowerX(), packet->getTowerY(), packet->getBuilder());
|
||||
|
||||
notifyListeners(&WorldListener::OnTowerAdd, newTower);
|
||||
}
|
||||
|
||||
void WorldClient::HandlePacket(const protocol::RemoveTowerPacket* packet) {
|
||||
game::TowerPtr tower = removeTower(packet->getTowerID());
|
||||
|
||||
if (tower != nullptr) {
|
||||
notifyListeners(&WorldListener::OnTowerRemove, tower);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
||||
@@ -41,6 +41,7 @@ void ServerConnexion::registerHandlers() {
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlaceTower, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::SendMobs, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this);
|
||||
}
|
||||
|
||||
bool ServerConnexion::updateSocket() {
|
||||
@@ -159,6 +160,8 @@ void ServerConnexion::HandlePacket(const protocol::PlaceTowerPacket* packet) {
|
||||
|
||||
game::TowerPtr tower = world->placeTowerAt(towerType, packet->getTowerX(), packet->getTowerY(), m_ID);
|
||||
|
||||
world->notifyListeners(&game::WorldListener::OnTowerAdd, tower);
|
||||
|
||||
protocol::WorldAddTowerPacket addTowerPacket(tower->getID(), packet->getTowerX(), packet->getTowerY(), packet->getTowerType(), m_ID);
|
||||
m_Server->broadcastPacket(&addTowerPacket);
|
||||
}
|
||||
@@ -179,6 +182,12 @@ void ServerConnexion::HandlePacket(const protocol::UpgradeTowerPacket* packet) {
|
||||
m_Server->broadcastPacket(packet);
|
||||
}
|
||||
|
||||
void ServerConnexion::HandlePacket(const protocol::RemoveTowerPacket* packet) {
|
||||
//TODO: verify the packet
|
||||
|
||||
m_Server->broadcastPacket(packet);
|
||||
}
|
||||
|
||||
ServerConnexion::~ServerConnexion() {
|
||||
if (GetDispatcher() != nullptr)
|
||||
GetDispatcher()->UnregisterHandler(this);
|
||||
|
||||
@@ -22,14 +22,20 @@ void ServerWorld::spawnMobs(game::MobType type, std::uint8_t level, game::Player
|
||||
enemyMobSpawn = &getTeam(game::TeamColor::Red).getSpawn();
|
||||
}
|
||||
|
||||
std::int32_t spawnCenterX = enemyMobSpawn->getCenterX();
|
||||
std::int32_t spawnCenterY = enemyMobSpawn->getCenterY();
|
||||
float spawnWidth = enemyMobSpawn->getWidth();
|
||||
float spawnHeight = enemyMobSpawn->getHeight();
|
||||
|
||||
std::int32_t minSpawnY = spawnCenterY - 2;
|
||||
std::int32_t maxSpawnY = spawnCenterY + 2;
|
||||
float spawnCenterX = enemyMobSpawn->getCenterX();
|
||||
float spawnCenterY = enemyMobSpawn->getCenterY();
|
||||
|
||||
std::int32_t minSpawnX = spawnCenterX - 2;
|
||||
std::int32_t maxSpawnX = spawnCenterX + 2;
|
||||
auto mobStats = getMobStats(type, level);
|
||||
auto mobSize = mobStats->getSize();
|
||||
|
||||
float minSpawnX = spawnCenterX - spawnWidth / 2.0f + mobSize.x / 2.0f;
|
||||
float maxSpawnX = spawnCenterX + spawnWidth / 2.0f - mobSize.x / 2.0f;
|
||||
|
||||
float minSpawnY = spawnCenterY - spawnHeight / 2.0f + mobSize.y / 2.0f;
|
||||
float maxSpawnY = spawnCenterY + spawnHeight / 2.0f - mobSize.y / 2.0f;
|
||||
|
||||
float mobX = utils::getRandomReal<float>(minSpawnX, maxSpawnX);
|
||||
float mobY = utils::getRandomReal<float>(minSpawnY, maxSpawnY);
|
||||
@@ -49,9 +55,5 @@ game::TowerPtr ServerWorld::placeTowerAt(game::TowerType type, std::int32_t x, s
|
||||
return tower;
|
||||
}
|
||||
|
||||
void ServerWorld::OnArrowShot(game::MobPtr target, game::Tower* shooter) {
|
||||
World::OnArrowShot(target, shooter);
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace td
|
||||
|
||||
@@ -39,6 +39,14 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -48,21 +56,29 @@ bool Circle::collidesWith(const Point& point) const {
|
||||
}
|
||||
|
||||
bool Circle::collidesWith(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 distanceSquared_ = distanceSquared(rect);
|
||||
|
||||
float distanceX = m_Center.getX() - closestX;
|
||||
float distanceY = m_Center.getY() - closestY;
|
||||
|
||||
float distanceSquared = (distanceX * distanceX) + (distanceY * distanceY);
|
||||
|
||||
return distanceSquared < m_Radius * m_Radius;
|
||||
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
|
||||
|
||||
@@ -28,7 +28,7 @@ static std::map<PacketType, PacketCreator> packets = {
|
||||
{PacketType::SpawnMob, []() -> PacketPtr {return std::make_unique<SpawnMobPacket>(); } },
|
||||
{PacketType::PlaceTower, []() -> PacketPtr {return std::make_unique<PlaceTowerPacket>(); } },
|
||||
{PacketType::WorldAddTower, []() -> PacketPtr {return std::make_unique<WorldAddTowerPacket>(); } },
|
||||
{PacketType::WorldRemoveTower, []() -> PacketPtr {return std::make_unique<WorldRemoveTowerPacket>(); } },
|
||||
{PacketType::RemoveTower, []() -> PacketPtr {return std::make_unique<RemoveTowerPacket>(); } },
|
||||
{PacketType::SendMobs, []() -> PacketPtr {return std::make_unique<SendMobsPacket>(); } },
|
||||
{PacketType::UpgradeTower, []() -> PacketPtr {return std::make_unique<UpgradeTowerPacket>(); } },
|
||||
};
|
||||
|
||||
@@ -485,13 +485,13 @@ void WorldAddTowerPacket::Deserialize(DataBuffer& data) {
|
||||
data >> m_TowerID >> m_TowerX >> m_TowerY >> m_TowerType >> m_Builder;
|
||||
}
|
||||
|
||||
DataBuffer WorldRemoveTowerPacket::Serialize() const {
|
||||
DataBuffer RemoveTowerPacket::Serialize() const {
|
||||
DataBuffer data;
|
||||
data << getID() << m_TowerID;
|
||||
return data;
|
||||
}
|
||||
|
||||
void WorldRemoveTowerPacket::Deserialize(DataBuffer& data) {
|
||||
void RemoveTowerPacket::Deserialize(DataBuffer& data) {
|
||||
data >> m_TowerID;
|
||||
}
|
||||
|
||||
@@ -543,7 +543,7 @@ REGISTER_DISPATCH_CLASS(ServerTpsPacket);
|
||||
REGISTER_DISPATCH_CLASS(SpawnMobPacket);
|
||||
REGISTER_DISPATCH_CLASS(PlaceTowerPacket);
|
||||
REGISTER_DISPATCH_CLASS(WorldAddTowerPacket);
|
||||
REGISTER_DISPATCH_CLASS(WorldRemoveTowerPacket);
|
||||
REGISTER_DISPATCH_CLASS(RemoveTowerPacket);
|
||||
REGISTER_DISPATCH_CLASS(SendMobsPacket);
|
||||
REGISTER_DISPATCH_CLASS(UpgradeTowerPacket);
|
||||
|
||||
|
||||
@@ -5,46 +5,43 @@ namespace td {
|
||||
namespace render {
|
||||
|
||||
void VertexCache::addData(std::uint64_t index, std::vector<float> positions, std::vector<float> colors) {
|
||||
ElementsIndex positionsIndexes;
|
||||
positionsIndexes.first = m_Positions.end();
|
||||
m_Positions.insert(m_Positions.end(), positions.begin(), positions.end());
|
||||
positionsIndexes.second = m_Positions.end() - 1;
|
||||
|
||||
ElementsIndex colorsIndexes;
|
||||
colorsIndexes.first = m_Colors.end();
|
||||
m_Colors.insert(m_Colors.end(), colors.begin(), colors.end());
|
||||
colorsIndexes.second = m_Colors.end() - 1;
|
||||
|
||||
m_Indexes.insert({ index, {positionsIndexes, colorsIndexes} });
|
||||
m_Indexes.insert({ index, {positions, colors} });
|
||||
m_VertexCount += colors.size(); // one color per vertex
|
||||
}
|
||||
|
||||
void VertexCache::removeData(std::uint64_t index) {
|
||||
auto it = m_Indexes.find(index);
|
||||
if (it != m_Indexes.end()) {
|
||||
DataIndex indexes = it->second;
|
||||
ElementsIndex positionsIndexes = indexes.first;
|
||||
ElementsIndex colorsIndexes = indexes.second;
|
||||
|
||||
m_Positions.erase(positionsIndexes.first, positionsIndexes.second);
|
||||
m_Colors.erase(colorsIndexes.first, colorsIndexes.second);
|
||||
|
||||
m_Indexes.erase(it);
|
||||
m_VertexCount -= it->second.color.size(); // one color per vertex
|
||||
}
|
||||
}
|
||||
|
||||
void VertexCache::clear() {
|
||||
m_Positions.clear();
|
||||
m_Colors.clear();
|
||||
m_Indexes.clear();
|
||||
m_VertexCount = 0;
|
||||
}
|
||||
|
||||
void VertexCache::updateVertexArray() {
|
||||
m_VertexArray = std::make_unique<GL::VertexArray>(m_Colors.size()); // one color per vertex
|
||||
m_VertexArray = std::make_unique<GL::VertexArray>(m_VertexCount); // one color per vertex
|
||||
|
||||
GL::VertexBuffer positionsBuffer(m_Positions, 2);
|
||||
Vector positions;
|
||||
positions.reserve(m_VertexCount * 2);
|
||||
|
||||
Vector colors;
|
||||
colors.reserve(m_VertexCount);
|
||||
|
||||
for (auto it = m_Indexes.begin(); it != m_Indexes.end(); it++) {
|
||||
const DataIndex& data = it->second;
|
||||
|
||||
positions.insert(positions.end(), data.position.begin(), data.position.end());
|
||||
colors.insert(colors.end(), data.color.begin(), data.color.end());
|
||||
}
|
||||
|
||||
GL::VertexBuffer positionsBuffer(positions, 2);
|
||||
positionsBuffer.addVertexAttribPointer(0, 2, 0);
|
||||
|
||||
GL::VertexBuffer colorsBuffer(m_Colors, 1);
|
||||
GL::VertexBuffer colorsBuffer(colors, 1);
|
||||
colorsBuffer.addVertexAttribPointer(1, 1, 0);
|
||||
|
||||
m_VertexArray->bind();
|
||||
|
||||
@@ -37,6 +37,7 @@ WorldRenderer::WorldRenderer(game::World* world, client::ClientGame* client) : m
|
||||
m_Renderer->setCamMovement({});
|
||||
m_TowerPlacePopup = std::make_unique<gui::TowerPlacePopup>(m_Client->getClient());
|
||||
m_MobTooltip = std::make_unique<gui::MobTooltip>(m_Client->getClient());
|
||||
m_Client->getWorld().bindListener(this);
|
||||
}
|
||||
|
||||
void WorldRenderer::updateCursorPos() {
|
||||
@@ -64,6 +65,18 @@ void WorldRenderer::update() {
|
||||
m_PopupOpened = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsMouseDoubleClicked(1)) removeTower();
|
||||
}
|
||||
|
||||
void WorldRenderer::removeTower() {
|
||||
glm::vec2 cursorPos = getCursorWorldPos();
|
||||
|
||||
game::TowerPtr clickedTower = m_World->getTower(cursorPos);
|
||||
|
||||
if (clickedTower != nullptr) {
|
||||
m_Client->getClient()->removeTower(clickedTower->getID());
|
||||
}
|
||||
}
|
||||
|
||||
void WorldRenderer::renderWorld() const {
|
||||
@@ -243,13 +256,13 @@ void WorldRenderer::detectMobHovering() const {
|
||||
m_MobTooltip->setMob(nullptr);
|
||||
}
|
||||
|
||||
void WorldRenderer::addTower(game::TowerPtr tower) {
|
||||
const WorldLoader::RenderData& renderData = WorldLoader::loadTowerModel(tower);
|
||||
void WorldRenderer::OnTowerAdd(game::TowerPtr tower) {
|
||||
WorldLoader::RenderData renderData = WorldLoader::loadTowerModel(tower);
|
||||
m_TowersCache.addData(tower->getID(), renderData.positions, renderData.colors);
|
||||
m_TowersCache.updateVertexArray();
|
||||
}
|
||||
|
||||
void WorldRenderer::removeTower(game::TowerPtr tower) {
|
||||
void WorldRenderer::OnTowerRemove(game::TowerPtr tower) {
|
||||
m_TowersCache.removeData(tower->getID());
|
||||
m_TowersCache.updateVertexArray();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "misc/Updater.h"
|
||||
#include "updater/Updater.h"
|
||||
|
||||
#include "misc/Platform.h"
|
||||
#include "misc/DataBuffer.h"
|
||||
|
||||
@@ -35,6 +35,9 @@ target("TowerDefense")
|
||||
end
|
||||
|
||||
else
|
||||
if is_os("linux") then
|
||||
add_links("dw")
|
||||
end
|
||||
add_cxflags("-pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wswitch-default -Wundef -Wno-unused")
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user