render entities

This commit is contained in:
2025-07-17 23:00:16 +02:00
parent b21439718b
commit b788caafa6
8 changed files with 228 additions and 158 deletions

View File

@@ -6,8 +6,8 @@
#include <td/Types.h> #include <td/Types.h>
#include <td/game/Team.h> #include <td/game/Team.h>
#include <vector>
#include <memory> #include <memory>
#include <vector>
namespace td { namespace td {
namespace game { namespace game {
@@ -42,8 +42,7 @@ typedef std::uint8_t MobLevel;
typedef std::vector<TowerType> TowerImmunities; typedef std::vector<TowerType> TowerImmunities;
typedef std::vector<EffectType> EffectImmunities; typedef std::vector<EffectType> EffectImmunities;
class MobStats { struct MobStats {
private:
float m_Damage; float m_Damage;
float m_Speed; float m_Speed;
Vec2f m_Size; Vec2f m_Size;
@@ -51,21 +50,6 @@ private:
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:
MobStats(float damage, float speed, Vec2f size, std::uint16_t moneyCost,
std::uint16_t expCost, std::uint16_t expReward,
std::uint16_t maxLife) : m_Damage(damage), m_Speed(speed),
m_Size(size), m_MoneyCost(moneyCost), m_ExpCost(expCost),
m_MaxLife(maxLife), m_ExpReward(expReward) {
}
float GetDamage() const { return m_Damage; }
float GetMovementSpeed() const { return m_Speed; }
const Vec2f& GetSize() const { return m_Size; }
std::uint16_t GetMoneyCost() const { return m_MoneyCost; }
std::uint16_t GetExpCost() const { return m_ExpCost; }
std::uint16_t GetExpReward() const { return m_ExpReward; }
std::uint16_t GetMaxLife() const { return m_MaxLife; }
}; };
struct EffectDuration { struct EffectDuration {
@@ -79,9 +63,10 @@ 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 : public utils::shape::Rectangle { class Mob : public utils::shape::Rectangle {
protected: protected:
float m_Health; float m_Health;
private:
private:
MobID m_ID; MobID m_ID;
PlayerID m_Sender; PlayerID m_Sender;
MobLevel m_Level; MobLevel m_Level;
@@ -97,30 +82,55 @@ private:
TeamCastle* m_CastleTarget; TeamCastle* m_CastleTarget;
// utils::CooldownTimer m_AttackTimer; // utils::CooldownTimer m_AttackTimer;
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_HitCooldown(0), m_CastleTarget(nullptr) {}
m_HitCooldown(0), m_CastleTarget(nullptr) {
} virtual ~Mob() {}
virtual MobType GetType() const = 0; virtual MobType GetType() const = 0;
virtual void Tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world) {}
virtual bool OnDeath(World* world) { return true; } virtual bool OnDeath(World* world) {
return true;
}
MobID GetMobID() const { return m_ID; } MobID GetMobID() const {
const TowerImmunities& GetTowerImmunities() const { return GetMobTowerImmunities(GetType(), m_Level); } return m_ID;
const EffectImmunities& GetEffectImmunities() const { return GetMobEffectImmunities(GetType(), m_Level); } }
PlayerID GetSender() const { return m_Sender; } const TowerImmunities& GetTowerImmunities() const {
MobLevel GetLevel() const { return m_Level; } return GetMobTowerImmunities(GetType(), m_Level);
const MobStats* GetStats() const { return GetMobStats(GetType(), m_Level); } }
void SetHealth(float newHealth) { m_Health = newHealth; } const EffectImmunities& GetEffectImmunities() const {
float GetHealth() const { return m_Health; } return GetMobEffectImmunities(GetType(), m_Level);
bool IsDead() const { return m_Health <= 0; } }
bool IsAlive() const { return m_Health > 0; } PlayerID GetSender() const {
const Tower* GetLastDamageTower() { return m_LastDamage; } return m_Sender;
bool HasReachedEnemyCastle() { return m_CastleTarget != nullptr; } }
MobLevel GetLevel() const {
return m_Level;
}
const MobStats* GetStats() const {
return GetMobStats(GetType(), m_Level);
}
void SetHealth(float newHealth) {
m_Health = newHealth;
}
float GetHealth() const {
return m_Health;
}
bool IsDead() const {
return m_Health <= 0;
}
bool IsAlive() const {
return m_Health > 0;
}
const Tower* GetLastDamageTower() {
return m_LastDamage;
}
bool HasReachedEnemyCastle() {
return m_CastleTarget != nullptr;
}
void Damage(float dmg, const Tower* damager) { void Damage(float dmg, const Tower* damager) {
m_Health = std::max(0.0f, m_Health - dmg); m_Health = std::max(0.0f, m_Health - dmg);
@@ -129,10 +139,12 @@ public:
} }
void Heal(float heal) { void Heal(float heal) {
m_Health = std::min(static_cast<float>(GetStats()->GetMaxLife()), m_Health + heal); m_Health = std::min(static_cast<float>(GetStats()->m_MaxLife), m_Health + heal);
} }
void SetMobReachedCastle(TeamCastle* castle) { m_CastleTarget = castle; } // used when mob is in front of the castle void SetMobReachedCastle(TeamCastle* castle) {
m_CastleTarget = castle;
} // used when mob is in front of the castle
bool IsImmuneTo(TowerType type); bool IsImmuneTo(TowerType type);
@@ -140,19 +152,34 @@ public:
void AddEffect(EffectType type, float durationSec, Tower* tower); void AddEffect(EffectType type, float durationSec, Tower* tower);
bool HasEffect(EffectType type); bool HasEffect(EffectType type);
bool HasTakenDamage() { return m_HitCooldown > 0; } bool HasTakenDamage() {
return m_HitCooldown > 0;
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; }
protected:
void InitMob() {
m_Health = static_cast<float>(GetStats()->GetMaxLife());
SetSize(GetStats()->GetSize().x, GetStats()->GetSize().y);
} }
private:
// returns a float between 0 and 1 excluded
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()));
}
Direction GetDirection() const {
return m_Direction;
}
void SetDirection(Direction dir) {
m_Direction = dir;
}
protected:
void InitMob() {
m_Health = static_cast<float>(GetStats()->m_MaxLife);
SetSize(GetStats()->m_Size.x, GetStats()->m_Size.y);
}
private:
void UpdateEffects(std::uint64_t delta, World* world); void UpdateEffects(std::uint64_t delta, World* world);
void AttackCastle(std::uint64_t delta, World* world); void AttackCastle(std::uint64_t delta, World* world);
void Move(std::uint64_t delta, World* world); void Move(std::uint64_t delta, World* world);
@@ -165,85 +192,42 @@ private:
typedef std::shared_ptr<Mob> MobPtr; typedef std::shared_ptr<Mob> MobPtr;
class Zombie : public Mob { template <MobType MT>
public: class ConcreteMob : public Mob {
Zombie(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); } public:
ConcreteMob(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) {
InitMob();
}
virtual MobType GetType() const { return MobType::Zombie; } virtual ~ConcreteMob() {}
virtual void Tick(std::uint64_t delta, World* world) {}
virtual constexpr MobType GetType() const {
return MT;
}
}; };
class Spider : public Mob { using Zombie = ConcreteMob<MobType::Zombie>;
public: using Spider = ConcreteMob<MobType::Spider>;
Spider(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); } using Skeleton = ConcreteMob<MobType::Skeleton>;
using PigMan = ConcreteMob<MobType::Pigman>;
virtual MobType GetType() const { return MobType::Spider; } using Creeper = ConcreteMob<MobType::Creeper>;
}; using Silverfish = ConcreteMob<MobType::Silverfish>;
using Blaze = ConcreteMob<MobType::Blaze>;
class Skeleton : public Mob { using Witch = ConcreteMob<MobType::Witch>;
public: using Slime = ConcreteMob<MobType::Slime>;
Skeleton(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); } using Giant = ConcreteMob<MobType::Giant>;
virtual MobType GetType() const { return MobType::Skeleton; }
};
class PigMan : public Mob {
public:
PigMan(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Pigman; }
};
class Creeper : public Mob {
public:
Creeper(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Creeper; }
};
class Silverfish : public Mob {
public:
Silverfish(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Silverfish; }
};
class Blaze : public Mob {
public:
Blaze(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Blaze; }
};
class Witch : public Mob {
public:
Witch(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Witch; }
};
class Slime : public Mob {
public:
Slime(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Slime; }
};
class Giant : public Mob {
public:
Giant(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Giant; }
};
namespace MobFactory { namespace MobFactory {
MobPtr CreateMob(MobID id, MobType type, std::uint8_t level, PlayerID sender); MobPtr CreateMob(MobID id, MobType type, std::uint8_t level, PlayerID sender);
std::string GetMobName(MobType type); std::string GetMobName(MobType type);
} } // namespace MobFactory
class MobListener { class MobListener {
public: public:
virtual void OnMobSpawn(Mob* mob) {} virtual void OnMobSpawn(Mob* mob) {}
virtual void OnMobDie(Mob* mob) {} virtual void OnMobDie(Mob* mob) {}
@@ -257,4 +241,3 @@ public:
} // namespace game } // namespace game
} // namespace td } // namespace td

View File

@@ -0,0 +1,23 @@
#pragma once
#include <td/render/Renderer.h>
#include <td/render/shader/EntityShader.h>
#include <td/game/World.h>
namespace td {
namespace render {
class EntityRenderer : public Renderer<shader::EntityShader> {
private:
const game::World& m_World;
std::unique_ptr<GL::VertexArray> m_EntityVao;
public:
EntityRenderer(Camera& a_Camera, const game::World& a_World);
virtual ~EntityRenderer();
virtual void Render() override;
};
} // namespace render
} // namespace td

View File

@@ -1,14 +1,12 @@
#pragma once #pragma once
#include <td/render/shader/ShaderProgram.h> #include <td/render/shader/CameraShaderProgram.h>
namespace td { namespace td {
namespace shader { namespace shader {
class EntityShader : public ShaderProgram { class EntityShader : public CameraShaderProgram {
private: private:
unsigned int m_LocationProjectionMatrix = 0;
unsigned int m_LocationViewMatrix = 0;
unsigned int m_LocationPosition = 0; unsigned int m_LocationPosition = 0;
unsigned int m_LocationColorEffect = 0; unsigned int m_LocationColorEffect = 0;
@@ -18,11 +16,7 @@ class EntityShader : public ShaderProgram {
public: public:
EntityShader(); EntityShader();
void LoadShader();
void SetColorEffect(const Vec3f& color); void SetColorEffect(const Vec3f& color);
void SetProjectionMatrix(const Mat4f& proj) const;
void SetViewMatrix(const Mat4f& view) const;
void SetModelPos(const Vec3f& pos) const; void SetModelPos(const Vec3f& pos) const;
}; };

View File

@@ -6,7 +6,9 @@
#include <td/game/World.h> #include <td/game/World.h>
#include <td/protocol/packet/Packets.h> #include <td/protocol/packet/Packets.h>
#include <td/render/renderer/WorldRenderer.h> #include <td/render/renderer/WorldRenderer.h>
#include <td/render/renderer/EntityRenderer.h>
namespace td { namespace td {
namespace game { namespace game {
@@ -202,8 +204,13 @@ int main(int argc, char** argv) {
td::render::Camera cam; td::render::Camera cam;
auto mob = std::make_shared<td::game::Zombie>(0, 0, 0);
mob->SetCenter({77, 13});
w.GetMobList().push_back(mob);
td::render::RenderPipeline renderer; td::render::RenderPipeline renderer;
renderer.AddRenderer<td::render::WorldRenderer>(cam, w); renderer.AddRenderer<td::render::WorldRenderer>(cam, w);
renderer.AddRenderer<td::render::EntityRenderer>(cam, w);
cam.SetCamPos({77, 25, 13}); cam.SetCamPos({77, 25, 13});
cam.UpdatePerspective(display.GetAspectRatio()); cam.UpdatePerspective(display.GetAspectRatio());

24
src/td/game/Mobs.cpp Normal file
View File

@@ -0,0 +1,24 @@
#include <td/game/Mobs.h>
namespace td {
namespace game {
const MobStats* GetMobStats(MobType type, std::uint8_t level) {
static MobStats stats;
return &stats;
}
const TowerImmunities& GetMobTowerImmunities(MobType type, std::uint8_t level) {
static TowerImmunities ti;
return ti;
}
const EffectImmunities& GetMobEffectImmunities(MobType type, std::uint8_t level) {
static EffectImmunities ei;
return ei;
}
} // namespace game
} // namespace td

View File

@@ -159,9 +159,9 @@ GL::VertexArray LoadTileSelectModel() {
colorVBO.AddVertexAttribPointer(1, 1, 0); colorVBO.AddVertexAttribPointer(1, 1, 0);
std::vector<unsigned int> indexes(positions.size() / 3, 0); std::vector<unsigned int> indexes(positions.size() / 3, 0);
for (size_t i = 0; i < indexes.size(); i++) { // for (size_t i = 0; i < indexes.size(); i++) {
indexes[i] = i + 1; // indexes[i] = i + 1;
} // }
GL::ElementBuffer indexVBO(indexes); GL::ElementBuffer indexVBO(indexes);
GL::VertexArray tileSelectVao(std::move(indexVBO)); GL::VertexArray tileSelectVao(std::move(indexVBO));
@@ -211,6 +211,36 @@ RenderData LoadTowerModel(game::TowerPtr tower) {
} }
GL::VertexArray LoadMobModel() {
std::vector<float> positions = {
-0.5, 0, -0.5,
-0.5, 0, 0.5,
0.5, 0, -0.5,
0.5, 0, -0.5,
-0.5, 0, 0.5,
0.5, 0, 0.5
};
std::vector<unsigned int> indexes(positions.size() / 3, 0);
// for (size_t i = 0; i < indexes.size(); i++) {
// indexes[i] = i + 1;
// }
GL::ElementBuffer indexVBO(indexes);
GL::VertexBuffer positionVBO(positions, POSITION_VERTEX_SIZE);
positionVBO.AddVertexAttribPointer(0, POSITION_VERTEX_SIZE, 0);
GL::VertexArray mobVao(std::move(indexVBO)); // each pos = 1 color
mobVao.Bind();
mobVao.BindVertexBuffer(std::move(positionVBO));
mobVao.Unbind();
return mobVao;
}
} // namespace WorldLoader } // namespace WorldLoader

View File

@@ -0,0 +1,26 @@
#include <td/render/renderer/EntityRenderer.h>
#include <td/render/loader/WorldLoader.h>
namespace td {
namespace render {
EntityRenderer::EntityRenderer(Camera& a_Camera, const game::World& a_World) : Renderer(a_Camera), m_World(a_World) {
m_EntityVao = std::make_unique<GL::VertexArray>(std::move(WorldLoader::LoadMobModel()));
m_Shader->Start();
m_Shader->SetColorEffect({1, 0, 1});
}
EntityRenderer::~EntityRenderer() {}
void EntityRenderer::Render() {
m_Shader->Start();
for (const auto& mob : m_World.GetMobList()) {
const auto mobCoords = mob->GetCenter();
m_Shader->SetModelPos({mobCoords.GetX(), 1, mobCoords.GetY()});
Renderer::Render(*m_EntityVao);
}
}
} // namespace render
} // namespace td

View File

@@ -53,16 +53,12 @@ static const char vertexSource[] = R"(
#version 330 #version 330
layout(location = 0) in vec3 position; layout(location = 0) in vec3 position;
layout(location = 1) in vec2 textureCoords;
uniform mat4 viewMatrix; uniform mat4 viewMatrix;
uniform mat4 projectionMatrix; uniform mat4 projectionMatrix;
uniform vec3 modelPosition; uniform vec3 modelPosition;
out vec2 pass_textureCoords;
void main(void){ void main(void){
pass_textureCoords = textureCoords;
gl_Position = projectionMatrix * viewMatrix * vec4(position + modelPosition, 1.0); gl_Position = projectionMatrix * viewMatrix * vec4(position + modelPosition, 1.0);
} }
)"; )";
@@ -70,16 +66,13 @@ void main(void){
static const char fragmentSource[] = R"( static const char fragmentSource[] = R"(
#version 330 #version 330
in vec2 pass_textureCoords;
out vec4 out_color; out vec4 out_color;
uniform vec3 ColorEffect; uniform vec3 ColorEffect;
uniform sampler2D textureSampler;
void main(void){ void main(void){
vec4 color = vec4(ColorEffect, 1.0) * texture(textureSampler, pass_textureCoords); vec4 color = vec4(ColorEffect, 1.0);
if (color.a <= 0.1) if (color.a <= 0.1)
discard; discard;
@@ -90,31 +83,21 @@ void main(void){
)"; )";
#endif #endif
EntityShader::EntityShader() : ShaderProgram() {} EntityShader::EntityShader() : CameraShaderProgram() {
void EntityShader::LoadShader() {
ShaderProgram::LoadProgram(vertexSource, fragmentSource); ShaderProgram::LoadProgram(vertexSource, fragmentSource);
} }
void EntityShader::GetAllUniformLocation() { void EntityShader::GetAllUniformLocation() {
CameraShaderProgram::GetAllUniformLocation();
m_LocationColorEffect = static_cast<unsigned int>(GetUniformLocation("ColorEffect")); m_LocationColorEffect = static_cast<unsigned int>(GetUniformLocation("ColorEffect"));
m_LocationViewMatrix = static_cast<unsigned int>(GetUniformLocation("viewMatrix"));
m_LocationPosition = static_cast<unsigned int>(GetUniformLocation("modelPosition")); m_LocationPosition = static_cast<unsigned int>(GetUniformLocation("modelPosition"));
m_LocationProjectionMatrix = static_cast<unsigned int>(GetUniformLocation("projectionMatrix"));
} }
void EntityShader::SetColorEffect(const Vec3f& color) { void EntityShader::SetColorEffect(const Vec3f& color) {
LoadVector(m_LocationColorEffect, color); LoadVector(m_LocationColorEffect, color);
} }
void EntityShader::SetProjectionMatrix(const Mat4f& proj) const {
LoadMat4(m_LocationProjectionMatrix, proj);
}
void EntityShader::SetViewMatrix(const Mat4f& view) const {
LoadMat4(m_LocationViewMatrix, view);
}
void EntityShader::SetModelPos(const Vec3f& pos) const { void EntityShader::SetModelPos(const Vec3f& pos) const {
LoadVector(m_LocationPosition, pos); LoadVector(m_LocationPosition, pos);
} }