and again

This commit is contained in:
2025-07-18 18:56:49 +02:00
parent 6d0e56eb46
commit 090ea962d3
19 changed files with 115 additions and 186 deletions

View File

@@ -176,6 +176,11 @@ Mat4f Look(const Vec3f& eye, const Vec3f& center, const Vec3f& up);
Mat4f Inverse(const Mat4f& mat);
template<typename T>
T Lerp(T v0, T v1, T t) {
return (T(1) - t) * v0 + t * v1;
}
} // namespace maths

View File

@@ -9,6 +9,10 @@
#include <memory>
#include <vector>
#include <sp/protocol/ConcreteMessage.h>
#include <sp/common/GenericHandler.h>
#include <sp/protocol/MessageFactory.h>
namespace td {
using Vec2fp = Vec2<FpFloat>;
@@ -65,152 +69,33 @@ 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 {
protected:
float m_Health;
class MobHandler;
private:
Vec2fp m_Position;
struct MobData {};
class Mob : public sp::MessageBase<MobType, MobHandler> {
public:
MobID m_ID;
PlayerID m_Sender;
MobLevel m_Level;
PlayerID m_Sender;
float m_Health;
Vec2fp m_Position;
Direction m_Direction;
std::vector<EffectDuration> m_Effects;
const Tower* m_LastDamage; // the last tower that damaged the mob
float m_HitCooldown;
// utils::Timer m_EffectFireTimer;
// utils::Timer m_EffectPoisonTimer;
// utils::Timer m_EffectHealTimer;
TeamCastle* m_CastleTarget;
// utils::CooldownTimer m_AttackTimer;
public:
Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level), m_HitCooldown(0), m_CastleTarget(nullptr) {}
MobPtr m_Next;
virtual ~Mob() {}
Mob() {}
virtual MobType GetType() const = 0;
virtual bool OnDeath(World* world) {
return true;
}
Vec2fp& GetPosition() {
return m_Position;
}
MobID GetMobID() const {
return m_ID;
}
const TowerImmunities& GetTowerImmunities() const {
return GetMobTowerImmunities(GetType(), m_Level);
}
const EffectImmunities& GetEffectImmunities() const {
return GetMobEffectImmunities(GetType(), m_Level);
}
PlayerID GetSender() const {
return m_Sender;
}
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) {
m_Health = std::max(0.0f, m_Health - dmg);
m_LastDamage = damager;
m_HitCooldown = 0.1;
}
void Heal(float 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
bool IsImmuneTo(TowerType type);
bool IsImmuneTo(EffectType type);
void AddEffect(EffectType type, float durationSec, Tower* tower);
bool HasEffect(EffectType type);
bool HasTakenDamage() {
return m_HitCooldown > 0;
}
// // 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 AttackCastle(std::uint64_t delta, World* world);
void Move(std::uint64_t delta, World* world);
void Walk(std::uint64_t delta, World* world);
void MoveBack(const TeamCastle& castle, World* world);
void ChangeDirection(const WalkableTile& tile, World* world);
bool IsTouchingCastle(const TeamCastle& castle) const;
EffectDuration& GetEffect(EffectType type);
Mob& operator=(const Mob& a_Other) = default;
};
typedef std::shared_ptr<Mob> MobPtr;
template <MobType MT>
class ConcreteMob : public Mob {
public:
ConcreteMob(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) {
InitMob();
}
virtual ~ConcreteMob() {}
virtual constexpr MobType GetType() const override {
return MT;
}
};
template <MobType ID>
using ConcreteMob = sp::ConcreteMessage<MobData, Mob, ID>;
using Zombie = ConcreteMob<MobType::Zombie>;
using Spider = ConcreteMob<MobType::Spider>;
@@ -223,16 +108,17 @@ using Witch = ConcreteMob<MobType::Witch>;
using Slime = ConcreteMob<MobType::Slime>;
using Giant = ConcreteMob<MobType::Giant>;
namespace MobFactory {
using AllMobs = std::tuple<Zombie, Spider, Skeleton, PigMan, Creeper, Silverfish, Blaze, Witch, Slime, Giant>;
MobPtr CreateMob(MobID id, MobType type, std::uint8_t level, PlayerID sender);
std::string GetMobName(MobType type);
class MobHandler : public sp::GenericHandler<AllMobs> {};
} // namespace MobFactory
using MobFactory = sp::MessageFactory<Mob, AllMobs>;
class MobListener {
public:
virtual void OnMobSpawn(Mob* mob) {}
virtual void OnMobSpawn(Mob* mob) {
MobHandler h;
}
virtual void OnMobDie(Mob* mob) {}
virtual void OnMobDamage(Mob* target, float damage, Tower* damager) {}

View File

@@ -21,6 +21,7 @@ class World {
TilePalette m_TilePalette;
sim::WorldSnapshot m_CurrentState;
sim::WorldSnapshot m_NextState;
private:
sim::WorldTicker m_Ticker;

View File

@@ -9,7 +9,7 @@
#include <sp/protocol/ConcreteMessage.h>
#include <sp/protocol/MessageDispatcher.h>
#include <sp/protocol/MessageFactory.h>
#include <sp/protocol/MessageHandler.h>
#include <sp/common/GenericHandler.h>
#include <td/Types.h>
#include <td/common/NonCopyable.h>
#include <td/protocol/command/CommandData.h>
@@ -33,7 +33,7 @@ class CommandHandler;
using CommandBase = sp::MessageBase<CommandID, CommandHandler>;
template <typename TData, CommandID ID>
using CommandMessage = sp::ConcreteMessage<TData, CommandID, ID, CommandHandler>;
using CommandMessage = sp::ConcreteMessage<TData, CommandBase, ID>;
namespace commands {
@@ -51,7 +51,7 @@ using UseItemCommand = CommandMessage<cdata::UseItem, CommandID::UseItem>;
using AllCommands = std::tuple<commands::EndCommand, commands::PlaceTowerCommand, commands::PlayerJoinCommand,
commands::SpawnTroopCommand, commands::TeamChangeCommand, commands::UpgradeTowerCommand, commands::UseItemCommand>;
class CommandHandler : public sp::MessageHandler<AllCommands> {};
class CommandHandler : public sp::GenericHandler<AllCommands> {};
using CommandDispatcher = sp::MessageDispatcher<CommandBase>;

View File

@@ -12,7 +12,7 @@
#include <sp/protocol/MessageBase.h>
#include <sp/protocol/MessageDispatcher.h>
#include <sp/protocol/MessageFactory.h>
#include <sp/protocol/MessageHandler.h>
#include <sp/common/GenericHandler.h>
namespace td {
namespace protocol {
@@ -37,7 +37,7 @@ using PacketBase = sp::MessageBase<PacketID, PacketHandler>;
template <typename TData, PacketID ID>
using PacketMessage = sp::ConcreteMessage<TData, PacketID, ID, PacketHandler>;
using PacketMessage = sp::ConcreteMessage<TData, PacketBase, ID>;
namespace packets {
@@ -61,7 +61,7 @@ using AllPackets = std::tuple<packets::BeginGamePacket, packets::ChatMessagePack
packets::KeepAlivePacket, packets::LockStepsPacket, packets::LoggingSuccessPacket, packets::PlayerJoinPacket,
packets::PlayerLeavePacket, packets::PlayerLoginPacket, packets::WorldHeaderPacket, packets::WorldDataPacket>;
class PacketHandler : public sp::MessageHandler<AllPackets> {};
class PacketHandler : public sp::GenericHandler<AllPackets> {};
using PacketDispatcher = sp::MessageDispatcher<PacketBase>;

View File

@@ -10,7 +10,8 @@ namespace render {
class BasicRenderer {
public:
virtual void Render() = 0;
virtual void Render(float a_Lerp) = 0;
virtual ~BasicRenderer() {}
void Render(const GL::VertexArray& a_Vao);
};
@@ -24,6 +25,11 @@ class Renderer : public BasicRenderer {
public:
Renderer(Camera& a_Camera);
virtual ~Renderer() {}
template <typename T>
float Lerp(const T& a_Mob, float a_LerpFactor, const std::function<float(const T&)>& a_MemberGetter) {
return static_cast<float>(maths::Lerp(a_MemberGetter(a_Mob), a_MemberGetter(*a_Mob.m_Next), a_LerpFactor));
}
};
class RenderPipeline {
@@ -32,7 +38,7 @@ class RenderPipeline {
public:
RenderPipeline();
~RenderPipeline() = default;
virtual ~RenderPipeline() {}
template <typename T, typename... Args>
void AddRenderer(Args&&... args) {
@@ -43,9 +49,9 @@ class RenderPipeline {
m_Renderers.clear();
}
void Render() {
void Render(float a_Lerp) {
for (auto& renderer : m_Renderers) {
renderer->Render();
renderer->Render(a_Lerp);
}
}
};

View File

@@ -16,7 +16,7 @@ class EntityRenderer : public Renderer<shader::EntityShader> {
EntityRenderer(Camera& a_Camera, const game::World& a_World);
virtual ~EntityRenderer();
virtual void Render() override;
virtual void Render(float a_Lerp) override;
};
} // namespace render

View File

@@ -10,14 +10,13 @@ namespace render {
class WorldRenderer : public Renderer<shader::WorldShader> {
private:
const game::World& m_World;
std::unique_ptr<GL::VertexArray> m_WorldVao;
public:
WorldRenderer(Camera& a_Camera, const game::World& a_World);
virtual ~WorldRenderer();
virtual void Render() override;
virtual void Render(float a_Lerp) override;
};
} // namespace render

View File

@@ -14,7 +14,7 @@ class CommandApply : public protocol::CommandHandler {
public:
CommandApply(const game::World& a_World, WorldSnapshot& a_Snapshot);
virtual void Handle(const protocol::cdata::SpawnTroop& a_SpawnTroop) override;
virtual void Handle(const protocol::commands::SpawnTroopCommand& a_SpawnTroop) override;
};
} // namespace sim

View File

@@ -17,9 +17,18 @@ class RealTimeSimulation {
std::size_t m_CurrentStep;
public:
/**
* \param a_StepTime in ms
*/
RealTimeSimulation(game::World& a_World, GameHistory&& a_History, std::uint64_t a_StepTime);
void Update();
/**
* \return the progress [0-1] between two steps
*/
float Update();
private:
void Step();
};
} // namespace sim

View File

@@ -23,12 +23,12 @@ class WorldTicker {
WorldTicker();
WorldSnapshot NextStep(
const game::World& a_World, const WorldSnapshot& a_PreviousState, const protocol::LockStep& a_LockStep, FpFloat a_Delta);
const game::World& a_World, WorldSnapshot& a_PreviousState, const protocol::LockStep& a_LockStep, FpFloat a_Delta);
private:
void ApplySteps(const game::World& a_World, WorldSnapshot& a_State, const protocol::LockStep& a_LockStep);
void Tick(const game::World& a_World, WorldSnapshot& a_State, FpFloat a_Delta);
WorldSnapshot CreateNext(const WorldSnapshot& a_PreviousState);
WorldSnapshot CreateNext(WorldSnapshot& a_PreviousState);
template <typename T>
void AddSystem() {