From 070749e6859243db3970941c11509be09021087e Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 21 Nov 2021 20:00:35 +0100 Subject: [PATCH] feat: implement shapes for entities --- include/game/Mobs.h | 14 ++----- include/game/Team.h | 33 ++++++++++++--- include/game/Towers.h | 9 ++-- include/game/World.h | 3 ++ include/misc/Shapes.h | 6 +++ src/game/Towers.cpp | 2 +- src/game/World.cpp | 69 ++++++++++++++++--------------- src/game/client/ClientGame.cpp | 2 +- src/game/server/ServerWorld.cpp | 8 ++-- src/render/WorldRenderer.cpp | 8 +--- src/render/loader/WorldLoader.cpp | 8 ++-- 11 files changed, 92 insertions(+), 70 deletions(-) diff --git a/include/game/Mobs.h b/include/game/Mobs.h index 9b01a75..5b28faf 100644 --- a/include/game/Mobs.h +++ b/include/game/Mobs.h @@ -2,6 +2,7 @@ #include "Towers.h" #include "Types.h" +#include "Team.h" #include #include @@ -75,7 +76,7 @@ const MobStats* getMobStats(MobType type, std::uint8_t level); const TowerImmunities& getMobTowerImmunities(MobType type, std::uint8_t level); const EffectImmunities& getMobEffectImmunities(MobType type, std::uint8_t level); -class Mob { +class Mob : public utils::shape::Rectangle{ protected: float m_Health; private: @@ -84,13 +85,12 @@ private: MobLevel m_Level; Direction m_Direction; std::vector m_Effects; - const Tower* m_LastDamage; // the tower that damaged the mob + const Tower* m_LastDamage; // the last tower that damaged the mob utils::Timer m_EffectFireTimer; utils::Timer m_EffectPoisonTimer; utils::Timer m_EffectHealTimer; - float m_X = 0, m_Y = 0; public: Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level), m_EffectFireTimer(1000), m_EffectPoisonTimer(1000), m_EffectHealTimer(1000) { @@ -101,7 +101,7 @@ public: 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 EffectImmunities& getEffectImmunities() const { return getMobEffectImmunities(getType(), m_Level); } @@ -116,12 +116,6 @@ public: 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(getStats()->getMaxLife()), m_Health + heal); } - 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(EffectType type); diff --git a/include/game/Team.h b/include/game/Team.h index b078634..4c804a2 100644 --- a/include/game/Team.h +++ b/include/game/Team.h @@ -2,6 +2,8 @@ #include "Types.h" +#include "misc/Shapes.h" + #include #include #include @@ -17,14 +19,33 @@ enum class TeamColor : std::int8_t { Blue }; -struct Spawn { - Direction direction; - std::int32_t x, y; +class Spawn : public utils::shape::Rectangle { +private: + Direction m_Direction; +public: + Spawn(){ + setWidth(5); + setHeight(5); + } + + Direction getDirection() const { return m_Direction; } + + void setDirection(Direction direction) { m_Direction = direction; } }; -struct TeamCastle { - std::int32_t x, y; - std::uint16_t life = 1000; +struct TeamCastle : public utils::shape::Rectangle{ +private: + 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 { diff --git a/include/game/Towers.h b/include/game/Towers.h index 97c99ac..9bcc3f4 100644 --- a/include/game/Towers.h +++ b/include/game/Towers.h @@ -5,6 +5,8 @@ #include #include "misc/Time.h" +#include "misc/Shapes.h" + #include "game/Types.h" namespace td { @@ -85,17 +87,16 @@ const TowerStats* getTowerStats(TowerType type, TowerLevel level); typedef std::uint16_t TowerID; -class Tower { +class Tower : public utils::shape::Point { private: TowerID m_ID; TowerType m_Type; - std::int32_t m_X, m_Y; TowerLevel m_Level{}; PlayerID m_Builder; protected: utils::CooldownTimer m_Timer; 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::Point(x, y), m_ID(id), m_Type(type), m_Builder(builder), m_Timer(getStats()->getDamageRate() * 1000) { // converting seconds to millis } @@ -112,8 +113,6 @@ public: } 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 TowerStats* getStats() const { return getTowerStats(m_Type, m_Level); } PlayerID getBuilder() const { return m_Builder; } diff --git a/include/game/World.h b/include/game/World.h index ffe5251..ca3f10d 100644 --- a/include/game/World.h +++ b/include/game/World.h @@ -134,6 +134,8 @@ protected: public: World(Game* game); + static constexpr std::uint8_t CastleWidth = 5, CastleHeight = 5; + bool loadMap(const protocol::WorldBeginDataPacket* worldHeader); bool loadMap(const protocol::WorldDataPacket* worldData); @@ -191,6 +193,7 @@ public: virtual void OnArrowShot(MobPtr target, Tower* shooter); private: void moveMobs(std::uint64_t delta); + void moveMob(MobPtr mob, std::uint64_t delta); void tickMobs(std::uint64_t delta); void cleanDeadMobs(); }; diff --git a/include/misc/Shapes.h b/include/misc/Shapes.h index ff209f6..fcdafdb 100644 --- a/include/misc/Shapes.h +++ b/include/misc/Shapes.h @@ -33,6 +33,9 @@ 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; } @@ -40,6 +43,9 @@ public: 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 setWidth(float width) { m_Width = width; } void setHeight(float height) { m_Height = height; } diff --git a/src/game/Towers.cpp b/src/game/Towers.cpp index 4cf411c..17db1af 100644 --- a/src/game/Towers.cpp +++ b/src/game/Towers.cpp @@ -9,7 +9,7 @@ namespace game { bool Tower::isMobInRange(MobPtr mob) { if (mob->isDead()) 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, TowerStats> TowerConstants = { diff --git a/src/game/World.cpp b/src/game/World.cpp index 5ab7433..cf0999e 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -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) { MobPtr mob = MobFactory::createMob(id, type, level, sender); - mob->setX(x); - mob->setY(y); + mob->setCenter({x, y}); mob->setDirection(dir); m_Mobs.push_back(mob); } @@ -131,38 +130,42 @@ void World::tickMobs(std::uint64_t delta) { void World::moveMobs(std::uint64_t delta) { for (MobPtr mob : m_Mobs) { - TilePtr tile = getTile(mob->getX(), mob->getY()); + TilePtr tile = getTile(mob->getCenter().getX(), mob->getCenter().getY()); if (tile != nullptr && tile->getType() == TileType::Walk) { WalkableTile* walkTile = dynamic_cast(tile.get()); mob->setDirection(walkTile->direction); } - float mobWalkSpeed = mob->getStats()->getMovementSpeed(); + moveMob(mob, delta); + } +} - float walkAmount = mobWalkSpeed * ((float)delta / 1000.0f); +void World::moveMob(MobPtr mob, std::uint64_t delta) { + float mobWalkSpeed = mob->getStats()->getMovementSpeed(); - if (mob->hasEffect(EffectType::Slowness)) - walkAmount *= 0.70; + float walkAmount = mobWalkSpeed * ((float)delta / 1000.0f); - switch (mob->getDirection()) { - case Direction::NegativeX: { - mob->setX(mob->getX() - walkAmount); - break; - } - case Direction::PositiveX: { - mob->setX(mob->getX() + walkAmount); - break; - } - case Direction::NegativeY: { - mob->setY(mob->getY() - walkAmount); - break; - } - case Direction::PositiveY: { - mob->setY(mob->getY() + walkAmount); - break; - } - } + if (mob->hasEffect(EffectType::Slowness)) + walkAmount *= 0.70; // walk 30% slower + + switch (mob->getDirection()) { + case Direction::NegativeX: { + mob->setCenterX(mob->getCenterX() - walkAmount); + break; + } + case Direction::PositiveX: { + mob->setCenterX(mob->getCenterX() + walkAmount); + break; + } + case Direction::NegativeY: { + mob->setCenterY(mob->getCenterY() - walkAmount); + break; + } + case Direction::PositiveY: { + mob->setCenterY(mob->getCenterY() + walkAmount); + break; + } } } @@ -245,16 +248,16 @@ void World::cleanDeadMobs() { for (std::size_t i = 0; i < m_Mobs.size(); i++) { MobPtr mob = m_Mobs[i]; if (mob->isDead()) { - mob->OnDeath(this); + if (mob->OnDeath(this)) { + //reward players + Player& sender = m_Game->getPlayerById(mob->getSender()); + sender.addExp(mob->getStats()->getExpReward()); - //reward players - Player& sender = m_Game->getPlayerById(mob->getSender()); - sender.addExp(mob->getStats()->getExpReward()); + Player& killer = m_Game->getPlayerById(mob->getLastDamageTower()->getBuilder()); + killer.addGold(mob->getStats()->getMoneyCost()); - Player& killer = m_Game->getPlayerById(mob->getLastDamageTower()->getBuilder()); - killer.addGold(mob->getStats()->getMoneyCost()); - - m_Mobs.erase(m_Mobs.begin() + i); + m_Mobs.erase(m_Mobs.begin() + i); + } } } } diff --git a/src/game/client/ClientGame.cpp b/src/game/client/ClientGame.cpp index 65a8be1..8889ffb 100644 --- a/src/game/client/ClientGame.cpp +++ b/src/game/client/ClientGame.cpp @@ -103,7 +103,7 @@ void ClientGame::HandlePacket(const protocol::WorldDataPacket* packet) { m_WorldRenderer.loadModels(); // set cam pos to player spawn 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() { diff --git a/src/game/server/ServerWorld.cpp b/src/game/server/ServerWorld.cpp index 2b907a9..e106b48 100644 --- a/src/game/server/ServerWorld.cpp +++ b/src/game/server/ServerWorld.cpp @@ -22,8 +22,8 @@ void ServerWorld::spawnMobs(game::MobType type, std::uint8_t level, game::Player enemyMobSpawn = &getTeam(game::TeamColor::Red).getSpawn(); } - std::int32_t spawnCenterX = enemyMobSpawn->x; - std::int32_t spawnCenterY = enemyMobSpawn->y; + std::int32_t spawnCenterX = enemyMobSpawn->getCenterX(); + std::int32_t spawnCenterY = enemyMobSpawn->getCenterY(); std::int32_t minSpawnY = 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(minSpawnX, maxSpawnX); float mobY = utils::getRandomReal(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_CurrentMobID++; diff --git a/src/render/WorldRenderer.cpp b/src/render/WorldRenderer.cpp index 48cc247..42da75e 100644 --- a/src/render/WorldRenderer.cpp +++ b/src/render/WorldRenderer.cpp @@ -74,7 +74,7 @@ void WorldRenderer::renderMobs() const { for (game::MobPtr mob : m_World->getMobList()) { Renderer::Model model; model.vao = m_MobVao.get(); - model.positon = { mob->getX(), mob->getY() }; + model.positon = { mob->getCenterX(), mob->getCenterY() }; m_Renderer->renderModel(model); } } @@ -235,11 +235,7 @@ void WorldRenderer::renderMobTooltip() const { void WorldRenderer::detectMobHovering() const { glm::vec2 cursorWorldPos = getCursorWorldPos(); for (game::MobPtr mob : m_World->getMobList()) { - // mob size is currently 1x1 for all mobs - 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) { + if(mob->collidesWith({cursorWorldPos.x, cursorWorldPos.y})){ m_MobTooltip->setMob(mob.get()); return; } diff --git a/src/render/loader/WorldLoader.cpp b/src/render/loader/WorldLoader.cpp index 07a5e1e..bdf09c3 100644 --- a/src/render/loader/WorldLoader.cpp +++ b/src/render/loader/WorldLoader.cpp @@ -97,8 +97,8 @@ GL::VertexArray loadWorldModel(const td::game::World* world) { for (int spawnColor = 0; spawnColor < 2; spawnColor++) { const game::Spawn& spawn = world->getTeam(game::TeamColor(spawnColor)).getSpawn(); - float fromX = spawn.x - 2, toX = spawn.x + 3; - float fromY = spawn.y - 2, toY = spawn.y + 3; + float fromX = spawn.getTopLeft().getX() , toX = spawn.getBottomRight().getX(); + float fromY = spawn.getTopLeft().getY() , toY = spawn.getBottomRight().getY(); positions.insert(positions.end(), { fromX, fromY, @@ -125,8 +125,8 @@ GL::VertexArray loadWorldModel(const td::game::World* world) { for (int castleColor = 0; castleColor < 2; castleColor++) { const game::TeamCastle& castle = world->getTeam(game::TeamColor(castleColor)).getCastle(); - float fromX = castle.x - 2, toX = castle.x + 3; - float fromY = castle.y - 2, toY = castle.y + 3; + float fromX = castle.getTopLeft().getX(), toX = castle.getBottomRight().getX(); + float fromY = castle.getTopLeft().getY(), toY = castle.getBottomRight().getY(); positions.insert(positions.end(), { fromX, fromY,