56 Commits

Author SHA1 Message Date
36f37b6548 Revert "Merge branch 'discord'"
This reverts commit e7b9a57723, reversing
changes made to 02b4aa3c91.

Revert "moved rapidjson files"

This reverts commit f5012f770c.
2023-06-21 23:36:20 +02:00
1dde1dbf1e fix vertex cache 2023-06-20 16:27:41 +02:00
f5012f770c moved rapidjson files 2023-06-08 12:30:05 +02:00
e7b9a57723 Merge branch 'discord' 2023-06-08 12:21:54 +02:00
02b4aa3c91 xmake add_files 2023-06-08 12:16:50 +02:00
f184982bc1 change release optimization 2023-06-07 12:39:58 +02:00
1cdc738839 refactor: rename zoom function 2023-06-07 12:36:31 +02:00
368bc450ce better cam controls 2023-06-07 12:33:10 +02:00
148b5f397a more vect operators 2023-06-07 12:32:24 +02:00
f62322752d use of td pi 2023-06-06 17:59:48 +02:00
fb9e125f16 refactor: format 2023-06-06 17:58:27 +02:00
b70e8f7790 approximative cam movement 2023-06-06 17:56:19 +02:00
39bdd0a11e remove useless pi digits 2023-06-06 17:17:00 +02:00
c95c8b7fde clamp camera + pi 2023-06-06 17:15:44 +02:00
e984ed9085 fixed cam distance 2023-06-06 17:04:17 +02:00
92035d7b9e remove useless variable 2023-06-06 13:09:02 +02:00
48841fa4e9 camera fixing 2023-06-06 13:07:42 +02:00
83ab8c70f0 cache transpose 2023-06-06 12:45:34 +02:00
ccdcdac7c6 working mouse picking 2023-06-06 12:36:05 +02:00
a2b5424888 fix inverse assert 2023-06-05 18:06:02 +02:00
a4fb56b549 camera yaw and pitch 2023-06-05 13:50:45 +02:00
22e62df04d remove unused variables 2023-06-05 13:17:04 +02:00
faf544f997 basic camera movement 2023-06-05 13:15:27 +02:00
b72f4a7673 fix inverted zoom 2023-06-05 13:12:43 +02:00
19c03010cb remove useless computation 2023-06-05 13:07:56 +02:00
41f8c152eb really bad controls 2023-06-04 13:02:41 +02:00
051c9d8744 fix format error 2023-06-04 12:42:58 +02:00
193e4db651 fix mouse picking 2023-06-03 20:43:40 +02:00
cb5f5a4cf8 fixing transpose 2023-06-03 19:46:37 +02:00
bc7e5914ce invert assert 2023-06-03 19:44:05 +02:00
0365902971 moved Mat4 definition 2023-06-03 19:40:50 +02:00
f2fcc348d7 more maths 2023-06-03 18:22:01 +02:00
95c92ec6c9 rename lookat function 2023-06-03 17:54:59 +02:00
721f15b601 fix tower rendering 2023-06-03 17:49:00 +02:00
3970103b01 kinda 3d 2023-06-03 17:41:46 +02:00
4e866c1032 shaders to 3d 2023-06-03 16:35:17 +02:00
ca268781fd shader better logging 2023-06-03 16:30:32 +02:00
a2d8984199 shader matrix support 2023-06-03 16:30:23 +02:00
e7f9ca2b6c fix maths warning 2023-06-03 16:23:56 +02:00
deb0075aac add maths utils 2023-06-02 17:54:58 +02:00
28b8659e16 fix linux compiling 2023-06-02 16:26:17 +02:00
0b9fc0520e fix compiling mingw 2023-06-02 16:19:42 +02:00
c54017c7be update presence 2023-06-02 13:34:01 +02:00
bbfe341d23 base discord rpc 2023-06-02 13:18:09 +02:00
14efe2cc39 simplified health bar display 2023-01-02 16:58:31 +01:00
fcda12e321 add hit "animation" 2023-01-02 16:37:18 +01:00
1200a6e087 moved TowerUpgradePopop into its own file 2023-01-02 15:56:20 +01:00
512fb23d0e add server mspt (+procotol format) 2023-01-02 15:07:34 +01:00
5a547b6514 move towers implementations 2023-01-02 14:47:02 +01:00
ed45995645 add mob send cooldown 2023-01-02 14:32:37 +01:00
0b6d826eba remove unused glm package 2023-01-02 13:55:54 +01:00
6d0c6be166 server side safe checks 2023-01-02 13:18:49 +01:00
222b79b40a indent with tabs 2023-01-02 13:05:43 +01:00
8f95b1a750 remove format warning 2023-01-02 12:27:08 +01:00
7d30017742 moved Color to Defines.h 2023-01-02 12:21:27 +01:00
386ea5b6ad forward declare Updater 2023-01-02 12:05:20 +01:00
121 changed files with 5560 additions and 4941 deletions

View File

@@ -1,7 +1,11 @@
#pragma once #pragma once
#include <cstdint>
namespace td { namespace td {
static constexpr float PI = 3.141592653f;
template<typename T> template<typename T>
struct Vec2 { struct Vec2 {
union { union {
@@ -14,11 +18,14 @@ struct Vec2 {
T g; T g;
}; };
Vec2(T X = 0, T Y = 0) : x(X), y(Y) {} constexpr Vec2(T X = 0, T Y = 0) : x(X), y(Y) {}
friend bool operator==(const Vec2& vec2, const Vec2& other) { return vec2.x == other.x && vec2.y == other.y; }
}; };
template<typename T>
inline bool operator==(const Vec2<T>& vec2, const Vec2<T>& other) {
return vec2.x == other.x && vec2.y == other.y;
}
template<typename T> template<typename T>
struct Vec3 { struct Vec3 {
union { union {
@@ -36,9 +43,45 @@ struct Vec3 {
T b; T b;
}; };
Vec3(T X = 0, T Y = 0, T Z = 0) : x(X), y(Y), z(Z) {} constexpr Vec3(T X = 0, T Y = 0, T Z = 0) : x(X), y(Y), z(Z) {}
}; };
template<typename T>
inline bool operator==(const Vec3<T>& vec3, const Vec3<T>& other) {
return vec3.x == other.x && vec3.y == other.y && vec3.z == other.z;
}
template<typename T>
struct Vec4 {
union {
T x;
T r;
};
union {
T y;
T g;
};
union {
T z;
T b;
};
union {
T w;
T a;
};
constexpr Vec4(Vec3<T> vec, T W = 1) : x(vec.x), y(vec.y), z(vec.z), w(W) {}
constexpr Vec4(T X = 0, T Y = 0, T Z = 0, T W = 0) : x(X), y(Y), z(Z), w(W) {}
};
template<typename T>
inline bool operator==(const Vec4<T>& vec4, const Vec4<T>& other) {
return vec4.x == other.x && vec4.y == other.y && vec4.z == other.z && vec4.w = other.w;
}
using Vec2i = Vec2<int>; using Vec2i = Vec2<int>;
using Vec2u = Vec2<unsigned int>; using Vec2u = Vec2<unsigned int>;
using Vec2f = Vec2<float>; using Vec2f = Vec2<float>;
@@ -49,4 +92,57 @@ using Vec3u = Vec3<unsigned int>;
using Vec3f = Vec3<float>; using Vec3f = Vec3<float>;
using Vec3d = Vec3<double>; using Vec3d = Vec3<double>;
using Vec4i = Vec4<int>;
using Vec4u = Vec4<unsigned int>;
using Vec4f = Vec4<float>;
using Vec4d = Vec4<double>;
using Color = Vec3<unsigned char>;
template<typename T>
struct Mat4 {
static const std::size_t MATRIX_SIZE = 4;
T x0, x1, x2, x3;
T y0, y1, y2, y3;
T z0, z1, z2, z3;
T w0, w1, w2, w3;
T operator[] (std::size_t offset) const {
return reinterpret_cast<const T*>(this)[offset];
}
T& operator[] (std::size_t offset) {
return reinterpret_cast<T*>(this)[offset];
}
T* data() {
return reinterpret_cast<T*>(this);
}
const T* data() const{
return reinterpret_cast<const T*>(this);
}
T at(std::size_t row, std::size_t column) const {
return operator[](row * MATRIX_SIZE + column);
}
T& at(std::size_t row, std::size_t column) {
return operator[](row * MATRIX_SIZE + column);
}
};
typedef Mat4<float> Mat4f;
typedef Mat4<int> Mat4i;
typedef Mat4<double> Mat4d;
template<typename T>
inline bool operator==(const Mat4<T>& mat, const Mat4<T>& other) {
return mat.x0 == other.x0 && mat.y0 == other.y0 && mat.z0 == other.z0 && mat.w0 == other.w0 &&
mat.x1 == other.x1 && mat.y1 == other.y1 && mat.z1 == other.z1 && mat.w1 == other.w1 &&
mat.x2 == other.x2 && mat.y2 == other.y2 && mat.z2 == other.z2 && mat.w2 == other.w2 &&
mat.x3 == other.x3 && mat.y3 == other.y3 && mat.z3 == other.z3 && mat.w3 == other.w3;
}
} // namespace td } // namespace td

View File

@@ -89,6 +89,7 @@ private:
Direction m_Direction; Direction m_Direction;
std::vector<EffectDuration> m_Effects; std::vector<EffectDuration> m_Effects;
const Tower* m_LastDamage; // the last tower that damaged the mob const Tower* m_LastDamage; // the last tower that damaged the mob
float m_HitCooldown;
utils::Timer m_EffectFireTimer; utils::Timer m_EffectFireTimer;
utils::Timer m_EffectPoisonTimer; utils::Timer m_EffectPoisonTimer;
@@ -99,7 +100,7 @@ private:
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_HitCooldown(0), m_EffectFireTimer(1000), m_EffectPoisonTimer(1000),
m_EffectHealTimer(1000), m_CastleTarget(nullptr), m_AttackTimer(1000) { m_EffectHealTimer(1000), m_CastleTarget(nullptr), m_AttackTimer(1000) {
} }
@@ -123,8 +124,16 @@ public:
const Tower* GetLastDamageTower() { return m_LastDamage; } const Tower* GetLastDamageTower() { return m_LastDamage; }
bool HasReachedEnemyCastle() { return m_CastleTarget != nullptr; } 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; } void Damage(float dmg, const Tower* damager) {
void Heal(float heal) { m_Health = std::min(static_cast<float>(GetStats()->GetMaxLife()), m_Health + heal); } 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()->GetMaxLife()), 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);
@@ -133,6 +142,8 @@ 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; }
float GetTileX() { return GetCenterX() - static_cast<float>(static_cast<std::int32_t>(GetCenterX())); } // 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())); } // 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

View File

@@ -136,7 +136,8 @@ private:
bool m_IsBigTower; bool m_IsBigTower;
public: public:
TowerInfo(std::string&& name, std::string&& description, bool big) : m_Name(std::move(name)), TowerInfo(std::string&& name, std::string&& description, bool big) : m_Name(std::move(name)),
m_Description(std::move(description)), m_IsBigTower(big) {} m_Description(std::move(description)), m_IsBigTower(big) {
}
const std::string& GetName() const { return m_Name; } const std::string& GetName() const { return m_Name; }
const std::string& GetDescription() const { return m_Description; } const std::string& GetDescription() const { return m_Description; }

View File

@@ -58,10 +58,6 @@ enum class TileType : std::uint8_t {
Ice,*/ Ice,*/
}; };
struct Color {
std::uint8_t r, g, b;
};
static constexpr Color BLACK{ 0, 0, 0 }; static constexpr Color BLACK{ 0, 0, 0 };
static constexpr Color WHITE{ 255, 255, 255 }; static constexpr Color WHITE{ 255, 255, 255 };

View File

@@ -12,6 +12,7 @@ private:
std::uint8_t m_ConnectionID; std::uint8_t m_ConnectionID;
std::string m_DisconnectReason; std::string m_DisconnectReason;
float m_ServerTPS; float m_ServerTPS;
float m_ServerMSPT;
int m_Ping = 0; int m_Ping = 0;
public: public:
ClientConnexion(); ClientConnexion();
@@ -25,6 +26,7 @@ public:
const std::string& GetDisconnectReason() const { return m_DisconnectReason; } const std::string& GetDisconnectReason() const { return m_DisconnectReason; }
float GetServerTPS() const { return m_ServerTPS; } float GetServerTPS() const { return m_ServerTPS; }
float GetServerMSPT() const { return m_ServerMSPT; }
int GetServerPing() const { return m_Ping; } int GetServerPing() const { return m_Ping; }
REMOVE_COPY(ClientConnexion); REMOVE_COPY(ClientConnexion);

View File

@@ -22,6 +22,7 @@ typedef std::map<std::uint8_t, ServerConnexion> ConnexionMap;
class TickCounter { class TickCounter {
private: private:
float m_TPS; float m_TPS;
float m_MSPT;
std::uint64_t m_LastTPSTime; std::uint64_t m_LastTPSTime;
std::uint8_t m_TickCount; std::uint8_t m_TickCount;
public: public:
@@ -46,6 +47,9 @@ public:
} }
float GetTPS() const { return m_TPS; } float GetTPS() const { return m_TPS; }
float GetMSPT() const { return m_MSPT; }
void SetMSPT(float mspt) { m_MSPT = mspt; }
}; };
class Server { class Server {

View File

@@ -11,8 +11,7 @@ namespace server {
class Server; class Server;
struct KeepAlive struct KeepAlive {
{
std::uint64_t keepAliveID = 0; std::uint64_t keepAliveID = 0;
std::uint64_t sendTime; std::uint64_t sendTime;
bool recievedResponse = false; bool recievedResponse = false;

View File

@@ -14,7 +14,7 @@ std::string format(const std::string& format, Args... args){
throw std::runtime_error("Error during formatting."); throw std::runtime_error("Error during formatting.");
} }
std::unique_ptr<char[]> buf(new char[size]); std::unique_ptr<char[]> buf(new char[size]);
snprintf(buf.get(), size, format.c_str(), args...); snprintf(buf.get(), static_cast<std::size_t>(size), format.c_str(), args...);
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
} }

177
include/misc/Maths.h Normal file
View File

@@ -0,0 +1,177 @@
#pragma once
#include "Defines.h"
#include <cmath>
namespace td {
//////////////////////////////////////////////////////////////////
// Operators //
//////////////////////////////////////////////////////////////////
template<typename T>
Vec2<T> operator+(const Vec2<T>& vect, const Vec2<T>& other) {
return {vect.x + other.x, vect.y + other.y};
}
template<typename T>
Vec2<T> operator- (const Vec2<T>& vect) {
return { -vect.x, -vect.y };
}
template<typename T>
Vec2<T> operator- (const Vec2<T>& vect, const Vec2<T>& other) {
return vect + (-other);
}
template<typename T>
Vec3<T> operator- (const Vec3<T>& vect) {
return { -vect.x, -vect.y, -vect.z };
}
template<typename T>
Vec3<T> operator+ (const Vec3<T>& vect, const Vec3<T>& other) {
return { vect.x + other.x, vect.y + other.y, vect.z + other.y };
}
template<typename T>
Vec3<T> operator- (const Vec3<T>& vect, const Vec3<T>& other) {
return vect + (-other);
}
template<typename T>
Vec4<T> operator- (const Vec4<T>& vect) {
return { -vect.x, -vect.y, -vect.z, -vect.w };
}
template<typename T>
Vec4<T> operator+ (const Vec4<T>& vect, const Vec4<T>& other) {
return { vect.x + other.x, vect.y + other.y, vect.z + other.y, vect.w + other.w };
}
template<typename T>
Vec4<T> operator- (const Vec4<T>& vect, const Vec4<T>& other) {
return vect + (-other);
}
//////////////////////////////////////////////////////////////////
// Vectors //
//////////////////////////////////////////////////////////////////
namespace maths {
template<typename T>
T Length(const Vec3<T>& vect) {
return std::sqrt(vect.x * vect.x + vect.y * vect.y + vect.z * vect.z);
}
template<typename T>
Vec3<T> Normalize(const Vec3<T>& vect) {
T length = Length(vect);
return { vect.x / length, vect.y / length, vect.z / length };
}
template<typename T>
Vec4<T> Normalize(const Vec4<T>& vect) {
T length = std::sqrt(vect.x * vect.x + vect.y * vect.y + vect.z * vect.z + vect.w * vect.w);
return { vect.x / length, vect.y / length, vect.z / length, vect.w / length };
}
template<typename T>
T Dot(const Vec3<T>& vect, const Vec3<T>& other) {
return vect.x * other.x + vect.y * other.y + vect.z * other.z;
}
template<typename T>
Vec3<T> Cross(const Vec3<T>& vect, const Vec3<T>& other) {
return {
vect.y * other.z - vect.z * other.y,
vect.z * other.x - vect.x * other.z,
vect.x * other.y - vect.y * other.x,
};
}
template<typename T>
T Dot(const Vec4<T>& vect, const Vec4<T>& other) {
return vect.x * other.x + vect.y * other.y + vect.z * other.z + vect.w * other.w;
}
template<typename T>
T Distance(const Vec3<T>& vect, const Vec3<T>& other) {
return Length(vect - other);
}
//////////////////////////////////////////////////////////////////
// Matricies //
//////////////////////////////////////////////////////////////////
template<typename T>
Vec4<T> Dot(const Mat4<T>& mat, const Vec4<T>& vect) {
return {
mat.x0 * vect.x + mat.x1 * vect.y + mat.x2 * vect.z + mat.x3 * vect.w,
mat.y0 * vect.x + mat.y1 * vect.y + mat.y2 * vect.z + mat.y3 * vect.w,
mat.z0 * vect.x + mat.z1 * vect.y + mat.z2 * vect.z + mat.z3 * vect.w,
mat.w0 * vect.x + mat.w1 * vect.y + mat.w2 * vect.z + mat.w3 * vect.w
};
}
template<typename T>
Mat4<T> Dot(const Mat4<T>& mat, const Mat4<T>& other) {
Mat4<T> result {};
for (std::size_t i = 0; i < Mat4<T>::MATRIX_SIZE; i++) {
for (std::size_t j = 0; j < Mat4<T>::MATRIX_SIZE; j++) {
for (std::size_t k = 0; k < Mat4<T>::MATRIX_SIZE; k++) {
result.at(i, j) += mat.at(i, k) * other.at(k, j);
}
}
}
return result;
}
template<typename T>
Mat4<T> Identity() {
Mat4<T> result{};
result.x0 = static_cast<T>(1);
result.y1 = static_cast<T>(1);
result.z2 = static_cast<T>(1);
result.w3 = static_cast<T>(1);
return result;
}
template<typename T>
Mat4<T> Transpose(const Mat4<T>& mat) {
Mat4<T> result;
result.x1 = mat.y0;
result.x2 = mat.z0;
result.x3 = mat.w0;
result.y0 = mat.x1;
result.y2 = mat.z1;
result.y3 = mat.w1;
result.z0 = mat.x2;
result.z1 = mat.y2;
result.z3 = mat.w2;
result.w0 = mat.x3;
result.w1 = mat.y3;
result.w2 = mat.z3;
result.x0 = mat.x0;
result.y1 = mat.y1;
result.z2 = mat.z2;
result.w3 = mat.w3;
return result;
}
Mat4f Perspective(float fovY, float aspectRatio, float zNear, float zFar);
Mat4f Look(const Vec3f& eye, const Vec3f& center, const Vec3f& up);
Mat4f Inverse(const Mat4f& mat);
} // namespace maths
} // namespace td

View File

@@ -49,9 +49,9 @@ enum class PacketType : std::uint8_t {
struct WorldHeader { struct WorldHeader {
game::TowerTileColorPalette m_TowerPlacePalette; game::TowerTileColorPalette m_TowerPlacePalette;
game::Color m_WalkablePalette; Color m_WalkablePalette;
std::vector<game::Color> m_DecorationPalette; std::vector<Color> m_DecorationPalette;
game::Color m_Background; Color m_Background;
game::SpawnColorPalette m_SpawnColorPalette; game::SpawnColorPalette m_SpawnColorPalette;
@@ -135,9 +135,9 @@ public:
virtual PacketType GetType() const { return PacketType::WorldBeginData; } virtual PacketType GetType() const { return PacketType::WorldBeginData; }
const game::TowerTileColorPalette& GetTowerTilePalette() const { return m_Header.m_TowerPlacePalette; } const game::TowerTileColorPalette& GetTowerTilePalette() const { return m_Header.m_TowerPlacePalette; }
const game::Color& GetWalkableTileColor() const { return m_Header.m_WalkablePalette; } const Color& GetWalkableTileColor() const { return m_Header.m_WalkablePalette; }
const std::vector<game::Color>& GetDecorationPalette() const { return m_Header.m_DecorationPalette; } const std::vector<Color>& GetDecorationPalette() const { return m_Header.m_DecorationPalette; }
const game::Color& GetBackgroundColor() const { return m_Header.m_Background; } const Color& GetBackgroundColor() const { return m_Header.m_Background; }
const game::Spawn& GetRedSpawn() const { return m_Header.m_RedSpawn; } const game::Spawn& GetRedSpawn() const { return m_Header.m_RedSpawn; }
const game::Spawn& GetBlueSpawn() const { return m_Header.m_BlueSpawn; } const game::Spawn& GetBlueSpawn() const { return m_Header.m_BlueSpawn; }
@@ -373,10 +373,11 @@ public:
class ServerTpsPacket : public Packet { class ServerTpsPacket : public Packet {
private: private:
float m_TPS; float m_TPS;
float m_MSPT;
std::uint64_t m_PacketSendTime; // used to calculate ping std::uint64_t m_PacketSendTime; // used to calculate ping
public: public:
ServerTpsPacket() {} ServerTpsPacket() {}
ServerTpsPacket(float tps, std::uint64_t sendTime) : m_TPS(tps), m_PacketSendTime(sendTime) {} ServerTpsPacket(float tps, float mspt, std::uint64_t sendTime) : m_TPS(tps), m_MSPT(mspt), m_PacketSendTime(sendTime) {}
virtual ~ServerTpsPacket() {} virtual ~ServerTpsPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
@@ -384,6 +385,7 @@ public:
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
float GetTPS() const { return m_TPS; } float GetTPS() const { return m_TPS; }
float GetMSPT() const { return m_MSPT; }
std::uint64_t GetPacketSendTime() const { return m_PacketSendTime; } std::uint64_t GetPacketSendTime() const { return m_PacketSendTime; }
virtual PacketType GetType() const { return PacketType::ServerTps; } virtual PacketType GetType() const { return PacketType::ServerTps; }
@@ -424,7 +426,8 @@ public:
SpawnMobPacket() {} SpawnMobPacket() {}
SpawnMobPacket(game::MobID id, game::MobType type, std::uint8_t level, game::PlayerID sender, SpawnMobPacket(game::MobID id, game::MobType type, std::uint8_t level, game::PlayerID sender,
float x, float y, game::Direction dir) : m_MobID(id), m_MobType(type), m_MobLevel(level), float x, float y, game::Direction dir) : m_MobID(id), m_MobType(type), m_MobLevel(level),
m_MobDirection(dir), m_Sender(sender), m_MobX(x), m_MobY(y) {} m_MobDirection(dir), m_Sender(sender), m_MobX(x), m_MobY(y) {
}
virtual ~SpawnMobPacket() {} virtual ~SpawnMobPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
@@ -449,7 +452,8 @@ private:
public: public:
PlaceTowerPacket() {} PlaceTowerPacket() {}
PlaceTowerPacket(std::int32_t x, std::int32_t y, game::TowerType type) : PlaceTowerPacket(std::int32_t x, std::int32_t y, game::TowerType type) :
m_TowerX(x), m_TowerY(y), m_TowerType(type) {} m_TowerX(x), m_TowerY(y), m_TowerType(type) {
}
virtual ~PlaceTowerPacket() {} virtual ~PlaceTowerPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
@@ -472,7 +476,8 @@ private:
public: public:
WorldAddTowerPacket() {} WorldAddTowerPacket() {}
WorldAddTowerPacket(game::TowerID id, std::int32_t x, std::int32_t y, game::TowerType type, game::PlayerID player) : WorldAddTowerPacket(game::TowerID id, std::int32_t x, std::int32_t y, game::TowerType type, game::PlayerID player) :
m_TowerID(id), m_TowerX(x), m_TowerY(y), m_TowerType(type), m_Builder(player) {} m_TowerID(id), m_TowerX(x), m_TowerY(y), m_TowerType(type), m_Builder(player) {
}
virtual ~WorldAddTowerPacket() {} virtual ~WorldAddTowerPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
@@ -534,7 +539,8 @@ private:
public: public:
MobState() {} MobState() {}
MobState(game::MobID id, const Point& position, float life, game::Direction direction) : MobState(game::MobID id, const Point& position, float life, game::Direction direction) :
m_MobID(id), m_MobPosition(position), m_MobLife(life), m_MobDirection(direction) {} m_MobID(id), m_MobPosition(position), m_MobLife(life), m_MobDirection(direction) {
}
game::MobID GetMobId() const { return m_MobID; } game::MobID GetMobId() const { return m_MobID; }
Point GetMobPosition() const { return m_MobPosition; } Point GetMobPosition() const { return m_MobPosition; }

View File

@@ -9,23 +9,39 @@
namespace td { namespace td {
namespace render { namespace render {
struct Camera {
Mat4f viewMatrix;
Mat4f projectionMatrix;
Mat4f InvViewMatrix;
Mat4f InvProjectionMatrix;
float CamDistance = 25.0f;
Vec3f CamPos {0, CamDistance, 0};
Vec2f CamLook {};
float m_Yaw = -PI / 2.0f;
float m_Pitch = -PI / 2.0f + 0.0000001f;
};
class Renderer { class Renderer {
public: public:
static constexpr float m_AnimationSpeed = 2.0f; static constexpr float m_AnimationSpeed = 2.0f;
static constexpr float m_MouseSensitivity = 200.0f;
struct Model { struct Model {
GL::VertexArray* vao; GL::VertexArray* vao;
Vec2f positon; Vec3f positon;
Vec3f color = { 1, 1, 1 };
}; };
private: private:
std::unique_ptr<shader::WorldShader> m_WorldShader; std::unique_ptr<shader::WorldShader> m_WorldShader;
std::unique_ptr<shader::EntityShader> m_EntityShader; std::unique_ptr<shader::EntityShader> m_EntityShader;
Vec2i m_WindowSize;
Vec3f m_BackgroundColor; Vec3f m_BackgroundColor;
bool m_IsometricView = true; Camera m_Camera {};
float m_IsometricShade = m_IsometricView;
Vec2f m_CamPos{};
public: public:
Renderer(); Renderer();
~Renderer(); ~Renderer();
@@ -38,18 +54,17 @@ public:
void RenderVAO(const GL::VertexArray& vao); void RenderVAO(const GL::VertexArray& vao);
void RenderModel(const Model& model); void RenderModel(const Model& model);
void SetZoom(float zoom); void AddZoom(float zoom);
void SetCamMovement(const Vec2f& mov); void SetCamAngularMovement(const Vec2f& mov);
void SetCamPos(const Vec2f& newPos); void SetCamMovement(const Vec2f& lastCursorPos, const Vec2f& currentCursorPos);
void SetIsometricView(bool isometric); // false = 2D true = Isometric void SetCamLook(const Vec2f& worldPos);
void SetBackgroundColor(const Vec3f& color) { m_BackgroundColor = color; } void SetBackgroundColor(const Vec3f& color) { m_BackgroundColor = color; }
Vec2f GetCursorWorldPos(const Vec2f& cursorPos, float aspectRatio, float zoom, float windowWidth, float windowHeight); Vec2f GetCursorWorldPos(const Vec2f& cursorPos, float windowWidth, float windowHeight);
private: private:
void UpdateIsometricView();
void UpdateIsometricFade();
void InitShaders(); void InitShaders();
void SetCamPos(const Vec3f& newPos);
}; };
} // namespace render } // namespace render

View File

@@ -6,6 +6,7 @@
#include "render/VertexCache.h" #include "render/VertexCache.h"
#include "render/gui/TowerPlacePopup.h" #include "render/gui/TowerPlacePopup.h"
#include "render/gui/TowerUpgradePopup.h"
#include "render/gui/MobTooltip.h" #include "render/gui/MobTooltip.h"
#include "render/gui/CastleTooltip.h" #include "render/gui/CastleTooltip.h"
@@ -38,6 +39,7 @@ private:
VertexCache m_TowersCache; VertexCache m_TowersCache;
std::unique_ptr<gui::TowerPlacePopup> m_TowerPlacePopup; std::unique_ptr<gui::TowerPlacePopup> m_TowerPlacePopup;
std::unique_ptr<gui::TowerUpgradePopup> m_TowerUpgradePopup;
std::unique_ptr<gui::MobTooltip> m_MobTooltip; std::unique_ptr<gui::MobTooltip> m_MobTooltip;
std::unique_ptr<gui::CastleTooltip> m_CastleTooltip; std::unique_ptr<gui::CastleTooltip> m_CastleTooltip;
public: public:
@@ -53,7 +55,7 @@ public:
void SetCamPos(float camX, float camY); void SetCamPos(float camX, float camY);
void MoveCam(float relativeX, float relativeY, float aspectRatio); void MoveCam(float relativeX, float relativeY);
void ChangeZoom(float zoom); void ChangeZoom(float zoom);
// WorldListener // WorldListener
@@ -67,7 +69,6 @@ private:
void RenderMobs() const; void RenderMobs() const;
void RenderTileSelect() const; void RenderTileSelect() const;
void RenderPopups(); void RenderPopups();
void RenderTowerUpgradePopup();
void RenderMobTooltip() const; void RenderMobTooltip() const;
void RenderCastleTooltip() const; void RenderCastleTooltip() const;
void DetectClick(); void DetectClick();

View File

@@ -0,0 +1,9 @@
#pragma once
namespace td {
namespace gui {
extern void RenderLifeProgress(float progress);
} // namespace gui
} // namespace td

View File

@@ -12,11 +12,15 @@ class SummonMenu : public GuiWidget {
private: private:
bool m_MenuOpened; bool m_MenuOpened;
int m_ImageWidth = 100; int m_ImageWidth = 100;
float m_Cooldown;
float m_LastCooldown;
static constexpr int m_MobTypeCount = static_cast<std::size_t>(td::game::MobType::MOB_COUNT); static constexpr int m_MobTypeCount = static_cast<std::size_t>(td::game::MobType::MOB_COUNT);
std::array<int, static_cast<std::size_t>(m_MobTypeCount)> m_Values; std::array<int, static_cast<std::size_t>(m_MobTypeCount)> m_Values;
public: public:
SummonMenu(client::Client* client); SummonMenu(client::Client* client);
void SetCooldown(float cooldown);
virtual void Render(); virtual void Render();
private: private:
void SetSummonMax(int valueIndex); void SetSummonMax(int valueIndex);

View File

@@ -0,0 +1,32 @@
#pragma once
#include "GuiWidget.h"
#include "Defines.h"
namespace td {
namespace gui {
class TowerUpgradePopup : public GuiWidget {
private:
Vec2f m_ClickWorldPos;
bool m_ShouldBeClosed;
bool m_Opened;
public:
TowerUpgradePopup(client::Client* client);
virtual void Render();
void SetClickPos(const Vec2f& worldPos);
bool IsPopupOpened();
private:
static constexpr float m_TowerPopupTileWidth = 200.0f;
static constexpr float m_TowerPopupTileHeight = 200.0f;
static constexpr float m_PlaceTowerButtonWidth = 150.0f;
static constexpr float m_PlaceTowerButtonHeight = 35.0f;
};
} // namespace gui
} // namespace td

View File

@@ -2,21 +2,28 @@
#include "GuiWidget.h" #include "GuiWidget.h"
#include "updater/Updater.h"
#include <future> #include <future>
#include <memory>
namespace td { namespace td {
namespace utils {
class Updater;
} // namespace utils
namespace gui { namespace gui {
class UpdateMenu : public GuiWidget { class UpdateMenu : public GuiWidget {
private: private:
bool m_Opened; bool m_Opened;
std::string m_Error; std::string m_Error;
utils::Updater m_Updater; std::unique_ptr<utils::Updater> m_Updater;
std::shared_future<bool> m_UpdateAvailable; std::shared_future<bool> m_UpdateAvailable;
public: public:
UpdateMenu(client::Client* client); UpdateMenu(client::Client* client);
virtual ~UpdateMenu();
virtual void Render(); virtual void Render();
private: private:

View File

@@ -6,24 +6,22 @@ namespace td {
namespace shader { namespace shader {
class EntityShader : public ShaderProgram { class EntityShader : public ShaderProgram {
private: private:
unsigned int m_LocationCam = 0; unsigned int m_LocationProjectionMatrix = 0;
unsigned int m_LocationZoom = 0; unsigned int m_LocationViewMatrix = 0;
unsigned int m_LocationAspectRatio = 0; unsigned int m_LocationPosition = 0;
unsigned int m_LocationTranslation = 0; unsigned int m_LocationColorEffect = 0;
unsigned int m_LocationViewtype = 0;
protected: protected:
virtual void GetAllUniformLocation(); virtual void GetAllUniformLocation();
public: public:
EntityShader(); EntityShader();
void LoadShader(); void LoadShader();
void SetCamPos(const Vec2f& camPos);
void SetZoom(float zoom); void SetColorEffect(const Vec3f& color);
void SetAspectRatio(float aspectRatio); void SetProjectionMatrix(const Mat4f& proj) const;
void SetModelPos(const Vec2f& modelPos); void SetViewMatrix(const Mat4f& view) const;
void SetIsometricView(float isometric); void SetModelPos(const Vec3f& pos) const;
}; };
} // namespace shader } // namespace shader

View File

@@ -27,6 +27,7 @@ protected:
void LoadVector(unsigned int location, const Vec2f& vector) const; void LoadVector(unsigned int location, const Vec2f& vector) const;
void LoadVector(unsigned int location, const Vec3f& vector) const; void LoadVector(unsigned int location, const Vec3f& vector) const;
void LoadBoolean(unsigned int location, bool value) const; void LoadBoolean(unsigned int location, bool value) const;
void LoadMat4(unsigned int location, const Mat4f& mat) const;
void CleanUp() const; void CleanUp() const;
private: private:

View File

@@ -7,16 +7,15 @@ namespace shader {
class WorldShader : public ShaderProgram { class WorldShader : public ShaderProgram {
private: private:
unsigned int m_LocationCam = 0, m_LocationZoom = 0, m_LocationAspectRatio = 0, m_LocationViewtype = 0; unsigned int m_LocationProjection = 0, m_LocationView = 0;
protected: protected:
void GetAllUniformLocation(); void GetAllUniformLocation();
public: public:
WorldShader(); WorldShader();
void LoadShader(); void LoadShader();
void SetCamPos(const Vec2f& camPos);
void SetZoom(float zoom); void SetProjectionMatrix(const Mat4f& proj) const;
void SetAspectRatio(float aspectRatio); void SetViewMatrix(const Mat4f& view) const;
void SetIsometricView(float isometric);
}; };
} // namespace shader } // namespace shader

View File

@@ -203,6 +203,7 @@ bool Mob::IsTouchingCastle(const TeamCastle& enemyCastle) const {
} }
void Mob::Tick(std::uint64_t delta, World* world) { void Mob::Tick(std::uint64_t delta, World* world) {
m_HitCooldown = std::max(0.0f, m_HitCooldown - static_cast<float>(delta / 1000.0f));
UpdateEffects(delta, world); UpdateEffects(delta, world);
Move(delta, world); Move(delta, world);
AttackCastle(delta, world); AttackCastle(delta, world);

View File

@@ -201,119 +201,5 @@ std::string GetTowerName(TowerType type) {
} }
} // namespace TowerFactory } // namespace TowerFactory
void ArcherTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
std::uint8_t arrowsShot = 0;
bool explosiveArrows = GetLevel().GetPath() == TowerPath::Bottom;
std::uint8_t arrows = explosiveArrows ? 2 : GetLevel().GetLevel();
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
world->GetWorldNotifier().NotifyListeners(&WorldListener::OnArcherTowerShot, mob, this);
m_Timer.ApplyCooldown();
arrowsShot++;
if (arrowsShot >= arrows)
break;
}
}
}
}
void IceTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
float damage = GetStats()->GetDamage();
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
mob->AddEffect(EffectType::Slowness, 1, this); // slowness for 1s every second
if (damage > 0)
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), damage, this);
m_Timer.ApplyCooldown();
}
}
}
}
void MageTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
mob->AddEffect(EffectType::Fire, GetLevel().GetLevel() * 3, this);
m_Timer.ApplyCooldown();
}
}
}
}
void PoisonTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
if (GetLevel().GetPath() == TowerPath::Bottom) {
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), GetStats()->GetDamage(), this);
} else {
float durationSec;
switch (GetLevel().GetLevel()) {
case 1:
durationSec = 5;
break;
case 2:
durationSec = 15;
break;
case 3:
durationSec = 30;
break;
case 4:
durationSec = 1e10; // about 3 million hours. It should be enough
break;
default:
durationSec = 0; // how did we get there ?
break;
}
mob->AddEffect(EffectType::Poison, durationSec, this);
}
m_Timer.ApplyCooldown();
}
}
}
}
void QuakeTower::Tick(std::uint64_t delta, World* world) {
}
void ZeusTower::Tick(std::uint64_t delta, World* world) {
}
void ArtilleryTower::Tick(std::uint64_t delta, World* world) {
}
void SorcererTower::Tick(std::uint64_t delta, World* world) {
}
void LeachTower::Tick(std::uint64_t delta, World* world) {
}
void TurretTower::Tick(std::uint64_t delta, World* world) {
}
void NecromancerTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game } // namespace game
} // namespace td } // namespace td

View File

@@ -27,6 +27,7 @@ void ClientConnexion::HandlePacket(const protocol::ConnexionInfoPacket* packet)
void ClientConnexion::HandlePacket(const protocol::ServerTpsPacket* packet) { void ClientConnexion::HandlePacket(const protocol::ServerTpsPacket* packet) {
m_ServerTPS = packet->GetTPS(); m_ServerTPS = packet->GetTPS();
m_ServerMSPT = packet->GetMSPT();
m_Ping = utils::GetTime() - packet->GetPacketSendTime(); m_Ping = utils::GetTime() - packet->GetPacketSendTime();
} }

View File

@@ -20,7 +20,7 @@ WorldClient::WorldClient(ClientGame* game) : game::World(game), protocol::Packet
void WorldClient::HandlePacket(const protocol::WorldBeginDataPacket* packet) { void WorldClient::HandlePacket(const protocol::WorldBeginDataPacket* packet) {
LoadMap(packet); LoadMap(packet);
if (m_Game->GetGameState() == game::GameState::Game) { if (m_Game->GetGameState() == game::GameState::Game) {
const game::Color& backgroundColor = GetBackgroundColor(); const Color& backgroundColor = GetBackgroundColor();
m_Game->GetRenderer()->SetBackgroundColor({ static_cast<float>(backgroundColor.r / 255.0f), static_cast<float>(backgroundColor.g / 255.0f), m_Game->GetRenderer()->SetBackgroundColor({ static_cast<float>(backgroundColor.r / 255.0f), static_cast<float>(backgroundColor.g / 255.0f),
static_cast<float>(backgroundColor.b / 255.0f) }); static_cast<float>(backgroundColor.b / 255.0f) });
} }

View File

@@ -26,6 +26,7 @@ void Server::StartThread() {
if (delta >= SERVER_TICK) { if (delta >= SERVER_TICK) {
Tick(delta); Tick(delta);
lastTime = td::utils::GetTime(); lastTime = td::utils::GetTime();
m_TickCounter.SetMSPT(lastTime - time);
std::uint64_t sleepTime = SERVER_TICK - (delta - SERVER_TICK); std::uint64_t sleepTime = SERVER_TICK - (delta - SERVER_TICK);
std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime)); std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
} }
@@ -85,7 +86,7 @@ void Server::Tick(std::uint64_t delta) {
m_Lobby.Tick(); m_Lobby.Tick();
m_Game.Tick(delta); m_Game.Tick(delta);
if (m_TickCounter.Update()) { if (m_TickCounter.Update()) {
protocol::ServerTpsPacket packet(m_TickCounter.GetTPS(), utils::GetTime()); protocol::ServerTpsPacket packet(m_TickCounter.GetTPS(), m_TickCounter.GetMSPT(), utils::GetTime());
BroadcastPacket(&packet); BroadcastPacket(&packet);
} }
} }

View File

@@ -10,6 +10,8 @@
#define KEEP_ALIVE_TIMEOUT 10 * 1000 // 10s #define KEEP_ALIVE_TIMEOUT 10 * 1000 // 10s
#define SAFE_CHECK(expr) if(expr) return
namespace td { namespace td {
namespace server { namespace server {
@@ -97,8 +99,8 @@ void ServerConnexion::HandlePacket(const protocol::PlayerLoginPacket* packet) {
} }
void ServerConnexion::HandlePacket(const protocol::SelectTeamPacket* packet) { void ServerConnexion::HandlePacket(const protocol::SelectTeamPacket* packet) {
if (m_Server->GetGame().GetGameState() != game::GameState::Lobby) SAFE_CHECK(m_Server->GetGame().GetGameState() != game::GameState::Lobby);
return;
if (static_cast<std::int8_t>(packet->GetSelectedTeam()) >= -1 || static_cast<std::int8_t>(packet->GetSelectedTeam()) <= 1) { if (static_cast<std::int8_t>(packet->GetSelectedTeam()) >= -1 || static_cast<std::int8_t>(packet->GetSelectedTeam()) <= 1) {
if (m_Player->GetTeamColor() == game::TeamColor::None) { // join a team if (m_Player->GetTeamColor() == game::TeamColor::None) { // join a team
m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player); m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player);
@@ -138,13 +140,13 @@ void ServerConnexion::InitConnection() {
protocol::ConnexionInfoPacket conPacket(m_ID); protocol::ConnexionInfoPacket conPacket(m_ID);
SendPacket(&conPacket); SendPacket(&conPacket);
if (m_Server->GetGame().GetGameState() == game::GameState::Game) { SAFE_CHECK(m_Server->GetGame().GetGameState() != game::GameState::Game);
protocol::WorldBeginDataPacket headerDataPacket(m_Server->GetGame().GetWorld()); protocol::WorldBeginDataPacket headerDataPacket(m_Server->GetGame().GetWorld());
protocol::WorldBeginDataPacket dataPacket(m_Server->GetGame().GetWorld()); protocol::WorldBeginDataPacket dataPacket(m_Server->GetGame().GetWorld());
SendPacket(&headerDataPacket); SendPacket(&headerDataPacket);
SendPacket(&dataPacket); SendPacket(&dataPacket);
} }
}
void ServerConnexion::HandlePacket(const protocol::PlaceTowerPacket* packet) { void ServerConnexion::HandlePacket(const protocol::PlaceTowerPacket* packet) {
game::TowerType towerType = packet->GetTowerType(); game::TowerType towerType = packet->GetTowerType();
@@ -153,12 +155,10 @@ void ServerConnexion::HandlePacket(const protocol::PlaceTowerPacket* packet) {
Vec2f towerPos = { static_cast<float>(packet->GetTowerX()), static_cast<float>(packet->GetTowerY()) }; Vec2f towerPos = { static_cast<float>(packet->GetTowerX()), static_cast<float>(packet->GetTowerY()) };
if (!world->CanPlaceLittleTower(towerPos, m_ID)) SAFE_CHECK(!world->CanPlaceLittleTower(towerPos, m_ID));
return;
if (towerInfo.IsBigTower()) if (towerInfo.IsBigTower())
if (!world->CanPlaceBigTower(towerPos, m_ID)) SAFE_CHECK(!world->CanPlaceBigTower(towerPos, m_ID));
return;
game::TowerPtr tower = world->PlaceTowerAt(towerType, packet->GetTowerX(), packet->GetTowerY(), m_ID); game::TowerPtr tower = world->PlaceTowerAt(towerType, packet->GetTowerX(), packet->GetTowerY(), m_ID);

View File

@@ -0,0 +1,25 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void ArcherTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
std::uint8_t arrowsShot = 0;
bool explosiveArrows = GetLevel().GetPath() == TowerPath::Bottom;
std::uint8_t arrows = explosiveArrows ? 2 : GetLevel().GetLevel();
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
world->GetWorldNotifier().NotifyListeners(&WorldListener::OnArcherTowerShot, mob, this);
m_Timer.ApplyCooldown();
arrowsShot++;
if (arrowsShot >= arrows)
break;
}
}
}
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void ArtilleryTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,22 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void IceTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
float damage = GetStats()->GetDamage();
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
mob->AddEffect(EffectType::Slowness, 1, this); // slowness for 1s every second
if (damage > 0)
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), damage, this);
m_Timer.ApplyCooldown();
}
}
}
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void LeachTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,19 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void MageTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
mob->AddEffect(EffectType::Fire, GetLevel().GetLevel() * 3, this);
m_Timer.ApplyCooldown();
}
}
}
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void NecromancerTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,45 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void PoisonTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
if (GetLevel().GetPath() == TowerPath::Bottom) {
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), GetStats()->GetDamage(), this);
} else {
float durationSec;
switch (GetLevel().GetLevel()) {
case 1:
durationSec = 5;
break;
case 2:
durationSec = 15;
break;
case 3:
durationSec = 30;
break;
case 4:
durationSec = 1e10; // about 3 million hours. It should be enough
break;
default:
durationSec = 0; // how did we get there ?
break;
}
mob->AddEffect(EffectType::Poison, durationSec, this);
}
m_Timer.ApplyCooldown();
}
}
}
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void QuakeTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void SorcererTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void TurretTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void ZeusTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

90
src/misc/Maths.cpp Normal file
View File

@@ -0,0 +1,90 @@
#include "misc/Maths.h"
#include <cassert>
namespace td {
namespace maths {
Mat4f Perspective(float fovY, float aspectRatio, float zNear, float zFar) {
const float tanHalfFovy = std::tan(fovY / 2.0f);
Mat4f result{};
result.x0 = 1.0f / (aspectRatio * tanHalfFovy);
result.y1 = 1.0f / (tanHalfFovy);
result.z2 = -(zFar + zNear) / (zFar - zNear);
result.z3 = -1.0f;
result.w2 = -(2.0f * zFar * zNear) / (zFar - zNear);
return result;
}
Mat4f Look(const Vec3f& eye, const Vec3f& front, const Vec3f& up) {
const Vec3f f = Normalize(front);
const Vec3f s = Normalize(Cross(f, up));
const Vec3f u = Cross(s, f);
Mat4f result = Identity<float>();
result.x0 = s.x;
result.y0 = s.y;
result.z0 = s.z;
result.x1 = u.x;
result.y1 = u.y;
result.z1 = u.z;
result.x2 = -f.x;
result.y2 = -f.y;
result.z2 = -f.z;
result.w0 = -Dot(s, eye);
result.w1 = -Dot(u, eye);
result.w2 = Dot(f, eye);
return result;
}
Mat4f Inverse(const Mat4f& mat) {
float s0 = mat.at(0, 0) * mat.at(1, 1) - mat.at(1, 0) * mat.at(0, 1);
float s1 = mat.at(0, 0) * mat.at(1, 2) - mat.at(1, 0) * mat.at(0, 2);
float s2 = mat.at(0, 0) * mat.at(1, 3) - mat.at(1, 0) * mat.at(0, 3);
float s3 = mat.at(0, 1) * mat.at(1, 2) - mat.at(1, 1) * mat.at(0, 2);
float s4 = mat.at(0, 1) * mat.at(1, 3) - mat.at(1, 1) * mat.at(0, 3);
float s5 = mat.at(0, 2) * mat.at(1, 3) - mat.at(1, 2) * mat.at(0, 3);
float c5 = mat.at(2, 2) * mat.at(3, 3) - mat.at(3, 2) * mat.at(2, 3);
float c4 = mat.at(2, 1) * mat.at(3, 3) - mat.at(3, 1) * mat.at(2, 3);
float c3 = mat.at(2, 1) * mat.at(3, 2) - mat.at(3, 1) * mat.at(2, 2);
float c2 = mat.at(2, 0) * mat.at(3, 3) - mat.at(3, 0) * mat.at(2, 3);
float c1 = mat.at(2, 0) * mat.at(3, 2) - mat.at(3, 0) * mat.at(2, 2);
float c0 = mat.at(2, 0) * mat.at(3, 1) - mat.at(3, 0) * mat.at(2, 1);
float det = s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0;
assert(det != 0 && "Determinant equals 0 !");
float invdet = 1.0 / det;
Mat4f result;
result.at(0, 0) = ( mat.at(1, 1) * c5 - mat.at(1, 2) * c4 + mat.at(1, 3) * c3) * invdet;
result.at(0, 1) = (-mat.at(0, 1) * c5 + mat.at(0, 2) * c4 - mat.at(0, 3) * c3) * invdet;
result.at(0, 2) = ( mat.at(3, 1) * s5 - mat.at(3, 2) * s4 + mat.at(3, 3) * s3) * invdet;
result.at(0, 3) = (-mat.at(2, 1) * s5 + mat.at(2, 2) * s4 - mat.at(2, 3) * s3) * invdet;
result.at(1, 0) = (-mat.at(1, 0) * c5 + mat.at(1, 2) * c2 - mat.at(1, 3) * c1) * invdet;
result.at(1, 1) = ( mat.at(0, 0) * c5 - mat.at(0, 2) * c2 + mat.at(0, 3) * c1) * invdet;
result.at(1, 2) = (-mat.at(3, 0) * s5 + mat.at(3, 2) * s2 - mat.at(3, 3) * s1) * invdet;
result.at(1, 3) = ( mat.at(2, 0) * s5 - mat.at(2, 2) * s2 + mat.at(2, 3) * s1) * invdet;
result.at(2, 0) = ( mat.at(1, 0) * c4 - mat.at(1, 1) * c2 + mat.at(1, 3) * c0) * invdet;
result.at(2, 1) = (-mat.at(0, 0) * c4 + mat.at(0, 1) * c2 - mat.at(0, 3) * c0) * invdet;
result.at(2, 2) = ( mat.at(3, 0) * s4 - mat.at(3, 1) * s2 + mat.at(3, 3) * s0) * invdet;
result.at(2, 3) = (-mat.at(2, 0) * s4 + mat.at(2, 1) * s2 - mat.at(2, 3) * s0) * invdet;
result.at(3, 0) = (-mat.at(1, 0) * c3 + mat.at(1, 1) * c1 - mat.at(1, 2) * c0) * invdet;
result.at(3, 1) = ( mat.at(0, 0) * c3 - mat.at(0, 1) * c1 + mat.at(0, 2) * c0) * invdet;
result.at(3, 2) = (-mat.at(3, 0) * s3 + mat.at(3, 1) * s1 - mat.at(3, 2) * s0) * invdet;
result.at(3, 3) = ( mat.at(2, 0) * s3 - mat.at(2, 1) * s1 + mat.at(2, 2) * s0) * invdet;
return result;
}
} // namespace maths
} // namespace td

View File

@@ -16,8 +16,7 @@ Socket::Socket(Type type)
: m_Blocking(false), : m_Blocking(false),
m_Type(type), m_Type(type),
m_Status(Disconnected), m_Status(Disconnected),
m_Handle(static_cast<SocketHandle>(INVALID_SOCKET)) m_Handle(static_cast<SocketHandle>(INVALID_SOCKET)) {
{
} }

View File

@@ -12,8 +12,7 @@ namespace td {
namespace network { namespace network {
UDPSocket::UDPSocket() UDPSocket::UDPSocket()
: Socket(Socket::UDP), m_Port(0) : Socket(Socket::UDP), m_Port(0) {
{
m_Handle = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); m_Handle = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
} }

View File

@@ -96,7 +96,7 @@ void PlayerLoginPacket::Deserialize(DataBuffer& data) {
DataBuffer WorldBeginDataPacket::Serialize(bool packetID) const { DataBuffer WorldBeginDataPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
const game::TowerTileColorPalette& towerTilePalette = m_Header.m_World->GetTowerTileColorPalette(); const game::TowerTileColorPalette& towerTilePalette = m_Header.m_World->GetTowerTileColorPalette();
const std::vector<game::Color>& decoTilePalette = m_Header.m_World->GetDecorationPalette(); const std::vector<Color>& decoTilePalette = m_Header.m_World->GetDecorationPalette();
WritePacketID(data, packetID); WritePacketID(data, packetID);
@@ -105,9 +105,9 @@ DataBuffer WorldBeginDataPacket::Serialize(bool packetID) const {
// deco color palette // deco color palette
std::size_t bufferSize = data.GetSize(); std::size_t bufferSize = data.GetSize();
data.Resize(bufferSize + decoTilePalette.size() * sizeof(game::Color)); data.Resize(bufferSize + decoTilePalette.size() * sizeof(Color));
memcpy(reinterpret_cast<std::uint8_t*>(data.data()) + bufferSize, decoTilePalette.data(), decoTilePalette.size() * sizeof(game::Color)); memcpy(reinterpret_cast<std::uint8_t*>(data.data()) + bufferSize, decoTilePalette.data(), decoTilePalette.size() * sizeof(Color));
data << m_Header.m_World->GetBackgroundColor(); data << m_Header.m_World->GetBackgroundColor();
@@ -135,7 +135,7 @@ void WorldBeginDataPacket::Deserialize(DataBuffer& data) {
std::uint16_t decoPaletteSize; std::uint16_t decoPaletteSize;
data >> decoPaletteSize; data >> decoPaletteSize;
std::size_t decoPalletteSizeByte = decoPaletteSize * sizeof(game::Color); std::size_t decoPalletteSizeByte = decoPaletteSize * sizeof(Color);
m_Header.m_DecorationPalette.resize(decoPaletteSize); m_Header.m_DecorationPalette.resize(decoPaletteSize);
@@ -425,12 +425,12 @@ DataBuffer ServerTpsPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_TPS << m_PacketSendTime; data << m_TPS << m_MSPT << m_PacketSendTime;
return data; return data;
} }
void ServerTpsPacket::Deserialize(DataBuffer& data) { void ServerTpsPacket::Deserialize(DataBuffer& data) {
data >> m_TPS >> m_PacketSendTime; data >> m_TPS >> m_MSPT >> m_PacketSendTime;
} }
DataBuffer SpawnMobPacket::Serialize(bool packetID) const { DataBuffer SpawnMobPacket::Serialize(bool packetID) const {

View File

@@ -10,6 +10,10 @@
#include <stdio.h> #include <stdio.h>
#include "misc/Time.h" #include "misc/Time.h"
#include "misc/Easing.h" #include "misc/Easing.h"
#include "misc/Maths.h"
#include <misc/Log.h>
#include <misc/Format.h>
namespace td { namespace td {
namespace render { namespace render {
@@ -22,21 +26,11 @@ Renderer::~Renderer() {
} }
void Renderer::UpdateIsometricView() {
float isometricEased = utils::EaseInOutExpo(m_IsometricShade);
m_WorldShader->Start();
m_WorldShader->SetIsometricView(isometricEased);
m_EntityShader->Start();
m_EntityShader->SetIsometricView(isometricEased);
}
void Renderer::InitShaders() { void Renderer::InitShaders() {
m_WorldShader = std::make_unique<shader::WorldShader>(); m_WorldShader = std::make_unique<shader::WorldShader>();
m_WorldShader->LoadShader(); m_WorldShader->LoadShader();
m_EntityShader = std::make_unique<shader::EntityShader>(); m_EntityShader = std::make_unique<shader::EntityShader>();
m_EntityShader->LoadShader(); m_EntityShader->LoadShader();
SetIsometricView(true);
UpdateIsometricView();
} }
// TODO : change loader check // TODO : change loader check
@@ -70,79 +64,99 @@ void Renderer::RenderVAO(const GL::VertexArray& vao) {
void Renderer::RenderModel(const Model& model) { void Renderer::RenderModel(const Model& model) {
m_EntityShader->Start(); m_EntityShader->Start();
m_EntityShader->SetModelPos(model.positon); m_EntityShader->SetModelPos(model.positon);
m_EntityShader->SetColorEffect(model.color);
model.vao->Bind(); model.vao->Bind();
glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(model.vao->GetVertexCount())); glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(model.vao->GetVertexCount()));
model.vao->Unbind(); model.vao->Unbind();
} }
void Renderer::UpdateIsometricFade() {
static std::uint64_t lastTime = utils::GetTime();
if (m_IsometricShade != static_cast<float>(m_IsometricView)) {
float step = static_cast<float>(utils::GetTime() - lastTime) / 1000.0f * m_AnimationSpeed;
if (m_IsometricShade < m_IsometricView) {
m_IsometricShade += step;
} else {
m_IsometricShade -= step;
}
m_IsometricShade = std::min(m_IsometricShade, 1.0f);
m_IsometricShade = std::max(m_IsometricShade, 0.0f);
UpdateIsometricView();
}
lastTime = utils::GetTime();
}
void Renderer::Prepare() { void Renderer::Prepare() {
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glClearColor(m_BackgroundColor.r, m_BackgroundColor.g, m_BackgroundColor.b, 0); glClearColor(m_BackgroundColor.r, m_BackgroundColor.g, m_BackgroundColor.b, 0);
UpdateIsometricFade();
} }
void Renderer::Resize(int width, int height) { void Renderer::Resize(int width, int height) {
m_Camera.projectionMatrix = maths::Perspective(80.0f / 180.0f * PI, static_cast<float>(width) / height, 0.1f, 160.0f);
m_Camera.InvProjectionMatrix = maths::Inverse(m_Camera.projectionMatrix);
m_WorldShader->Start(); m_WorldShader->Start();
m_WorldShader->SetAspectRatio(static_cast<float>(width) / height); m_WorldShader->SetProjectionMatrix(m_Camera.projectionMatrix);
m_EntityShader->Start(); m_EntityShader->Start();
m_EntityShader->SetAspectRatio(static_cast<float>(width) / height); m_WorldShader->SetProjectionMatrix(m_Camera.projectionMatrix);
m_WindowSize = { width, height };
glViewport(0, 0, width, height); glViewport(0, 0, width, height);
} }
void Renderer::SetZoom(float zoom) { void Renderer::AddZoom(float zoom) {
m_Camera.CamPos.y = std::max(1.0f, m_Camera.CamPos.y - zoom);
m_Camera.CamDistance = std::max(1.0f, m_Camera.CamDistance - zoom);
SetCamLook(m_Camera.CamLook);
}
void Renderer::SetCamAngularMovement(const Vec2f& mov) {
m_Camera.m_Pitch = std::clamp(m_Camera.m_Pitch - mov.y / m_MouseSensitivity, -PI / 2.0f + 0.0000001f, -PI / 12.0f);
m_Camera.m_Yaw += mov.x / m_MouseSensitivity;
SetCamLook(m_Camera.CamLook);
}
void Renderer::SetCamMovement(const Vec2f& lastCursorPos, const Vec2f& currentCursorPos) {
Vec2f worldLastCursorPos = GetCursorWorldPos(lastCursorPos, m_WindowSize.x, m_WindowSize.y);
Vec2f worldCurrentCursorPos = GetCursorWorldPos(currentCursorPos, m_WindowSize.x, m_WindowSize.y);
Vec2f movement = worldCurrentCursorPos - worldLastCursorPos;
SetCamLook(m_Camera.CamLook - movement);
}
void Renderer::SetCamPos(const Vec3f& newPos) {
Vec3f front = {
std::cos(m_Camera.m_Yaw) * std::cos(m_Camera.m_Pitch),
std::sin(m_Camera.m_Pitch),
std::sin(m_Camera.m_Yaw) * std::cos(m_Camera.m_Pitch)
};
m_Camera.CamPos = newPos;
m_Camera.viewMatrix = maths::Look(m_Camera.CamPos, front, { 0, 1, 0 });
m_Camera.InvViewMatrix = maths::Transpose(maths::Inverse(m_Camera.viewMatrix)); // why transpose ? I don't know
m_WorldShader->Start(); m_WorldShader->Start();
m_WorldShader->SetZoom(zoom); m_WorldShader->SetViewMatrix(m_Camera.viewMatrix);
m_EntityShader->Start(); m_EntityShader->Start();
m_EntityShader->SetZoom(zoom); m_EntityShader->SetViewMatrix(m_Camera.viewMatrix);
} }
void Renderer::SetCamMovement(const Vec2f& mov) { void Renderer::SetCamLook(const Vec2f& worldPos) {
m_CamPos.x += mov.x * (1 - m_IsometricView) + (0.5 * mov.x - mov.y) * m_IsometricView; static const float WORLD_HEIGHT = 0;
m_CamPos.y += -mov.y * (1 - m_IsometricView) + (-0.5 * mov.x - mov.y) * m_IsometricView;
SetCamPos(m_CamPos); m_Camera.CamLook = worldPos;
Vec3f front = {
std::cos(m_Camera.m_Yaw) * std::cos(m_Camera.m_Pitch),
std::sin(m_Camera.m_Pitch),
std::sin(m_Camera.m_Yaw) * std::cos(m_Camera.m_Pitch)
};
SetCamPos({
-m_Camera.CamDistance * front.x + m_Camera.CamLook.x,
-m_Camera.CamDistance * front.y + WORLD_HEIGHT,
-m_Camera.CamDistance * front.z + m_Camera.CamLook.y
});
} }
void Renderer::SetCamPos(const Vec2f& newPos) { Vec2f Renderer::GetCursorWorldPos(const Vec2f& cursorPos, float windowWidth, float windowHeight) {
m_CamPos = newPos;
m_WorldShader->Start();
m_WorldShader->SetCamPos(newPos);
m_EntityShader->Start();
m_EntityShader->SetCamPos(newPos);
}
void Renderer::SetIsometricView(bool isometric) { float relativeX = (cursorPos.x / windowWidth * 2) - 1.0f;
m_IsometricView = isometric; float relativeY = 1.0f - (cursorPos.y / windowHeight * 2);
}
Vec2f Renderer::GetCursorWorldPos(const Vec2f& cursorPos, float aspectRatio, float zoom, float windowWidth, float windowHeight) { Vec4f rayClip{ relativeX, relativeY, -1.0f, 1.0f };
float isometricEased = utils::EaseInOutExpo(m_IsometricShade);
float relativeX = (cursorPos.x / windowWidth * 2) - 1; Vec4f rayEye = maths::Dot(m_Camera.InvProjectionMatrix, rayClip);
float relativeY = (cursorPos.y / windowHeight * 2) - 1;
float deltaX = relativeX * aspectRatio / zoom; rayEye = { rayEye.x, rayEye.y, -1.0f, 0.0f };
float deltaY = relativeY / zoom;
float worldX = m_CamPos.x + deltaX * (1 - isometricEased) + (0.5 * deltaX + deltaY) * isometricEased; Vec4f rayWorld = maths::Dot(m_Camera.InvViewMatrix, rayEye);
float worldY = m_CamPos.y + deltaY * (1 - isometricEased) + (-0.5 * deltaX + deltaY) * isometricEased;
return { worldX, worldY }; float lambda = -m_Camera.CamPos.y / rayWorld.y;
return { lambda * rayWorld.x + m_Camera.CamPos.x, lambda * rayWorld.z + m_Camera.CamPos.z };
} }

View File

@@ -4,6 +4,8 @@
namespace td { namespace td {
namespace render { namespace render {
const static int VERTEX_SIZE = 3;
void VertexCache::AddData(std::uint64_t index, std::vector<float> positions, std::vector<float> colors) { void VertexCache::AddData(std::uint64_t index, std::vector<float> positions, std::vector<float> colors) {
m_Indexes.insert({ index, {positions, colors} }); m_Indexes.insert({ index, {positions, colors} });
m_VertexCount += colors.size(); // one color per vertex m_VertexCount += colors.size(); // one color per vertex
@@ -12,8 +14,8 @@ void VertexCache::AddData(std::uint64_t index, std::vector<float> positions, std
void VertexCache::RemoveData(std::uint64_t index) { void VertexCache::RemoveData(std::uint64_t index) {
auto it = m_Indexes.find(index); auto it = m_Indexes.find(index);
if (it != m_Indexes.end()) { if (it != m_Indexes.end()) {
m_Indexes.erase(it);
m_VertexCount -= it->second.color.size(); // one color per vertex m_VertexCount -= it->second.color.size(); // one color per vertex
m_Indexes.erase(it);
} }
} }
@@ -26,7 +28,7 @@ void VertexCache::UpdateVertexArray() {
m_VertexArray = std::make_unique<GL::VertexArray>(m_VertexCount); // one color per vertex m_VertexArray = std::make_unique<GL::VertexArray>(m_VertexCount); // one color per vertex
Vector positions; Vector positions;
positions.reserve(m_VertexCount * 2); positions.reserve(m_VertexCount * VERTEX_SIZE);
Vector colors; Vector colors;
colors.reserve(m_VertexCount); colors.reserve(m_VertexCount);
@@ -38,8 +40,8 @@ void VertexCache::UpdateVertexArray() {
colors.insert(colors.end(), data.color.begin(), data.color.end()); colors.insert(colors.end(), data.color.begin(), data.color.end());
} }
GL::VertexBuffer positionsBuffer(positions, 2); GL::VertexBuffer positionsBuffer(positions, VERTEX_SIZE);
positionsBuffer.AddVertexAttribPointer(0, 2, 0); positionsBuffer.AddVertexAttribPointer(0, VERTEX_SIZE, 0);
GL::VertexBuffer colorsBuffer(colors, 1); GL::VertexBuffer colorsBuffer(colors, 1);
colorsBuffer.AddVertexAttribPointer(1, 1, 0); colorsBuffer.AddVertexAttribPointer(1, 1, 0);

View File

@@ -32,9 +32,8 @@ void WorldRenderer::LoadModels() {
} }
WorldRenderer::WorldRenderer(game::World* world, client::ClientGame* client) : m_Client(client), m_Renderer(m_Client->GetRenderer()), m_World(world), m_Zoom(0.1) { WorldRenderer::WorldRenderer(game::World* world, client::ClientGame* client) : m_Client(client), m_Renderer(m_Client->GetRenderer()), m_World(world), m_Zoom(0.1) {
m_Renderer->SetZoom(m_Zoom);
m_Renderer->SetCamMovement({});
m_TowerPlacePopup = std::make_unique<gui::TowerPlacePopup>(m_Client->GetClient()); m_TowerPlacePopup = std::make_unique<gui::TowerPlacePopup>(m_Client->GetClient());
m_TowerUpgradePopup = std::make_unique<gui::TowerUpgradePopup>(m_Client->GetClient());
m_MobTooltip = std::make_unique<gui::MobTooltip>(m_Client->GetClient()); m_MobTooltip = std::make_unique<gui::MobTooltip>(m_Client->GetClient());
m_CastleTooltip = std::make_unique<gui::CastleTooltip>(m_Client->GetClient()); m_CastleTooltip = std::make_unique<gui::CastleTooltip>(m_Client->GetClient());
m_Client->GetWorldClient().GetWorldNotifier().BindListener(this); m_Client->GetWorldClient().GetWorldNotifier().BindListener(this);
@@ -47,22 +46,29 @@ void WorldRenderer::UpdateCursorPos() {
void WorldRenderer::Update() { void WorldRenderer::Update() {
if (m_WorldVao == nullptr) if (m_WorldVao == nullptr)
return; return;
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
if (io.MouseDown[0] && !ImGui::IsAnyItemActive()) {
if (io.MouseDown[0] && !ImGui::IsAnyItemActive() && !ImGui::IsAnyItemHovered()) {
ImVec2 mousePos = ImGui::GetIO().MousePos;
ImVec2 mouseDelta = ImGui::GetIO().MouseDelta; ImVec2 mouseDelta = ImGui::GetIO().MouseDelta;
const float relativeX = mouseDelta.x / (float)Display::GetWindowWidth() * 2; m_Renderer->SetCamMovement({mousePos.x - mouseDelta.x, mousePos.y - mouseDelta.y}, { mousePos.x, mousePos.y });
const float relativeY = mouseDelta.y / (float)Display::GetWindowHeight() * 2;
MoveCam(relativeX, relativeY, Display::GetAspectRatio());
} }
if (io.MouseDown[1] && !ImGui::IsAnyItemActive() && !ImGui::IsAnyItemHovered()) {
ImVec2 mouseDelta = ImGui::GetIO().MouseDelta;
m_Renderer->SetCamAngularMovement({ mouseDelta.x, mouseDelta.y });
}
if (io.MouseWheel != 0) { if (io.MouseWheel != 0) {
ChangeZoom(io.MouseWheel); ChangeZoom(io.MouseWheel);
} }
UpdateCursorPos(); UpdateCursorPos();
if (ImGui::IsMouseClicked(0)) { if (ImGui::IsMouseClicked(0)) {
if (!m_PopupOpened) { if (!m_TowerUpgradePopup->IsPopupOpened()) {
m_HoldCursorPos = { io.MousePos.x, io.MousePos.y }; m_HoldCursorPos = { io.MousePos.x, io.MousePos.y };
} else {
m_PopupOpened = false;
} }
} }
@@ -87,7 +93,8 @@ 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->GetCenterX(), mob->GetCenterY() }; model.positon = { mob->GetCenterX(), 0, mob->GetCenterY() };
model.color = mob->HasTakenDamage() ? Vec3f{ 1, 0.5, 0.5 } : Vec3f{ 1, 1, 1 };
m_Renderer->RenderModel(model); m_Renderer->RenderModel(model);
} }
} }
@@ -104,14 +111,14 @@ void WorldRenderer::RenderTileSelect() const {
Renderer::Model tileSelectModel; Renderer::Model tileSelectModel;
tileSelectModel.vao = m_SelectTileVao.get(); tileSelectModel.vao = m_SelectTileVao.get();
tileSelectModel.positon = { std::floor(m_CursorPos.x), std::floor(m_CursorPos.y) }; tileSelectModel.positon = { std::floor(m_CursorPos.x), 0, std::floor(m_CursorPos.y) };
m_Renderer->RenderModel(tileSelectModel); m_Renderer->RenderModel(tileSelectModel);
} }
void WorldRenderer::RenderPopups() { void WorldRenderer::RenderPopups() {
m_TowerPlacePopup->Render(); m_TowerPlacePopup->Render();
RenderTowerUpgradePopup(); m_TowerUpgradePopup->Render();
} }
void WorldRenderer::Render() { void WorldRenderer::Render() {
@@ -135,30 +142,23 @@ void WorldRenderer::RenderTooltips() const {
RenderCastleTooltip(); RenderCastleTooltip();
} }
void WorldRenderer::MoveCam(float relativeX, float relativeY, float aspectRatio) { void WorldRenderer::MoveCam(float relativeX, float relativeY) {
if (m_WorldVao == nullptr) if (m_WorldVao == nullptr)
return; return;
float movementX = -relativeX / m_Zoom * aspectRatio;
float movementY = relativeY / m_Zoom;
m_Renderer->SetCamMovement({ movementX, movementY });
} }
void WorldRenderer::ChangeZoom(float zoomStep) { void WorldRenderer::ChangeZoom(float zoomStep) {
if (m_WorldVao == nullptr) if (m_WorldVao == nullptr)
return; return;
static float sensibility = 1.5f;
if (zoomStep < 0) { m_Renderer->AddZoom(zoomStep);
m_Zoom /= -zoomStep * sensibility;
} else {
m_Zoom *= zoomStep * sensibility;
}
m_Renderer->SetZoom(m_Zoom);
m_Renderer->SetCamMovement({});
} }
void WorldRenderer::Click() { void WorldRenderer::Click() {
const game::TowerPtr tower = m_Client->GetWorld().GetTower(GetClickWorldPos()); const game::TowerPtr tower = m_Client->GetWorld().GetTower(GetClickWorldPos());
m_TowerPlacePopup->SetClickPos(GetClickWorldPos()); m_TowerPlacePopup->SetClickPos(GetClickWorldPos());
m_TowerUpgradePopup->SetClickPos(GetClickWorldPos());
if (tower != nullptr) { // there is a tower here if (tower != nullptr) { // there is a tower here
ImGui::OpenPopup("TowerUpgrade"); ImGui::OpenPopup("TowerUpgrade");
} else if (m_Client->GetWorld().CanPlaceLittleTower(GetClickWorldPos(), m_Client->GetPlayer()->GetID())) { } else if (m_Client->GetWorld().CanPlaceLittleTower(GetClickWorldPos(), m_Client->GetPlayer()->GetID())) {
@@ -168,70 +168,7 @@ void WorldRenderer::Click() {
void WorldRenderer::SetCamPos(float camX, float camY) { void WorldRenderer::SetCamPos(float camX, float camY) {
m_CamPos = { camX, camY }; m_CamPos = { camX, camY };
m_Renderer->SetCamPos(m_CamPos); m_Renderer->SetCamLook({ camX, camY });
}
void WorldRenderer::RenderTowerUpgradePopup() {
if (ImGui::BeginPopup("TowerUpgrade")) {
m_PopupOpened = true;
game::TowerPtr tower = m_Client->GetWorld().GetTower(GetClickWorldPos());
if (tower == nullptr) {
ImGui::EndPopup();
return;
}
ImGui::Text("Tower : %s", game::TowerFactory::GetTowerName(tower->GetType()).c_str());
for (int y = 0; y < 3; y++) { // path: 0 -> top 1 -> middle 2 -> bottom
for (int x = 0; x < 4; x++) { // level: 1, 2, 3, 4
if (x > 0)
ImGui::SameLine();
std::uint8_t currentLevel = x + 1;
game::TowerPath currentPath = game::TowerPath(y);
const game::TowerStats* towerStats = game::GetTowerStats(tower->GetType(), { currentLevel, currentPath });
game::TowerPath towerPath = tower->GetLevel().GetPath();
bool disabled = towerStats == nullptr;
int towerLevel = tower->GetLevel().GetLevel();
bool alreadyUpgraded = currentLevel <= towerLevel;
bool canUpgrade = (towerLevel + 1) == currentLevel;
if (canUpgrade && towerPath != game::TowerPath::Base) {
if (currentPath != towerPath) {
canUpgrade = false;
}
}
ImGui::PushID(x * 4 + y);
if (disabled) {
ImGui::BeginDisabled();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::Button("", ImVec2(100, 100));
ImGui::PopStyleColor();
ImGui::EndDisabled();
} else if (alreadyUpgraded) {
ImGui::BeginDisabled();
ImGui::Button("Already", ImVec2(100, 100));
ImGui::EndDisabled();
} else if (canUpgrade) {
if (ImGui::Button("Upgrade", ImVec2(100, 100))) {
m_Client->GetClient()->UpgradeTower(tower->GetID(), { currentLevel, currentPath });
}
} else {
ImGui::BeginDisabled();
ImGui::Button("Locked", ImVec2(100, 100));
ImGui::EndDisabled();
}
ImGui::PopID();
}
}
ImGui::EndPopup();
}
} }
void WorldRenderer::DetectClick() { void WorldRenderer::DetectClick() {
@@ -294,11 +231,11 @@ void WorldRenderer::OnTowerRemove(game::TowerPtr tower) {
Vec2f WorldRenderer::GetCursorWorldPos() const { Vec2f WorldRenderer::GetCursorWorldPos() const {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
return m_Renderer->GetCursorWorldPos({ io.MousePos.x, io.MousePos.y }, Display::GetAspectRatio(), m_Zoom, Display::GetWindowWidth(), Display::GetWindowHeight()); return m_Renderer->GetCursorWorldPos({ io.MousePos.x, io.MousePos.y }, Display::GetWindowWidth(), Display::GetWindowHeight());
} }
Vec2f WorldRenderer::GetClickWorldPos() const { Vec2f WorldRenderer::GetClickWorldPos() const {
return m_Renderer->GetCursorWorldPos(m_LastClicked, Display::GetAspectRatio(), m_Zoom, Display::GetWindowWidth(), Display::GetWindowHeight()); return m_Renderer->GetCursorWorldPos(m_LastClicked, Display::GetWindowWidth(), Display::GetWindowHeight());
} }
} // namespace render } // namespace render

View File

@@ -1,5 +1,6 @@
#include "render/gui/CastleTooltip.h" #include "render/gui/CastleTooltip.h"
#include "render/gui/imgui/imgui.h" #include "render/gui/imgui/imgui.h"
#include "render/gui/LifeProgress.h"
#include "render/WorldRenderer.h" #include "render/WorldRenderer.h"
@@ -15,12 +16,18 @@ CastleTooltip::CastleTooltip(client::Client* client) : GuiWidget(client) {
void CastleTooltip::Render() { void CastleTooltip::Render() {
if (m_Castle == nullptr) return; if (m_Castle == nullptr) return;
if (ImGui::GetIO().KeyShift) {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::PushStyleColor(ImGuiCol_Text, render::WorldRenderer::GetImGuiTeamColor(m_Castle->GetTeam()->GetColor())); ImGui::PushStyleColor(ImGuiCol_Text, render::WorldRenderer::GetImGuiTeamColor(m_Castle->GetTeam()->GetColor()));
ImGui::Text("Castle : "); ImGui::Text("Castle : ");
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::Text("\tCastle HP : %i/%i", static_cast<int>(m_Castle->GetLife()), game::TeamCastle::CastleMaxLife); ImGui::Text("\tCastle HP : %i/%i", static_cast<int>(m_Castle->GetLife()), game::TeamCastle::CastleMaxLife);
ImGui::EndTooltip(); ImGui::EndTooltip();
} else {
ImGui::BeginTooltip();
RenderLifeProgress(m_Castle->GetLife() / static_cast<float>(game::TeamCastle::CastleMaxLife));
ImGui::EndTooltip();
}
} }
} // namespace gui } // namespace gui

View File

@@ -18,9 +18,6 @@ void FrameMenu::Render() {
if (ImGui::Checkbox("V-Sync", &m_VSync)) { if (ImGui::Checkbox("V-Sync", &m_VSync)) {
SDL_GL_SetSwapInterval(m_VSync); SDL_GL_SetSwapInterval(m_VSync);
} }
if (ImGui::Checkbox("Vue Isometrique ?", &m_IsometricView)) {
GetClient()->GetRenderer()->SetIsometricView(m_IsometricView);
}
#if !defined(NDEBUG) #if !defined(NDEBUG)
ImGui::Checkbox("Demo Window", &m_ShowDemoWindow); ImGui::Checkbox("Demo Window", &m_ShowDemoWindow);

View File

@@ -85,6 +85,7 @@ void GameMenu::ShowLobbyProgress() {
void GameMenu::ShowTPS() { void GameMenu::ShowTPS() {
ImGui::Text("Server TPS : %.1f", GetClient()->GetConnexion().GetServerTPS()); ImGui::Text("Server TPS : %.1f", GetClient()->GetConnexion().GetServerTPS());
ImGui::Text("Server MSPT : %i", (int)GetClient()->GetConnexion().GetServerMSPT());
ImGui::Text("Server Ping : %i", GetClient()->GetConnexion().GetServerPing()); ImGui::Text("Server Ping : %i", GetClient()->GetConnexion().GetServerPing());
} }

View File

@@ -0,0 +1,15 @@
#include "render/gui/LifeProgress.h"
#include "render/gui/imgui/imgui.h"
namespace td {
namespace gui {
void RenderLifeProgress(float progress) {
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, { 1 - progress, progress, 0, 1 });
ImGui::ProgressBar(progress, { 100, 25 }, "");
ImGui::PopStyleColor();
}
} // namespace gui
} // namespace td

View File

@@ -1,5 +1,6 @@
#include "render/gui/MobTooltip.h" #include "render/gui/MobTooltip.h"
#include "render/gui/imgui/imgui.h" #include "render/gui/imgui/imgui.h"
#include "render/gui/LifeProgress.h"
#include "render/WorldRenderer.h" #include "render/WorldRenderer.h"
@@ -19,6 +20,7 @@ void MobTooltip::Render() {
// TODO: add sender null check // TODO: add sender null check
if (ImGui::GetIO().KeyShift) {
const game::Player* sender = GetClient()->GetGame().GetPlayerById(m_Mob->GetSender()); const game::Player* sender = GetClient()->GetGame().GetPlayerById(m_Mob->GetSender());
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::Text("Sender :"); ImGui::Text("Sender :");
@@ -38,6 +40,11 @@ void MobTooltip::Render() {
ImGui::Text("\tEXP cost : %i", m_Mob->GetStats()->GetExpCost()); ImGui::Text("\tEXP cost : %i", m_Mob->GetStats()->GetExpCost());
ImGui::Text("\tEXP reward : %i", m_Mob->GetStats()->GetExpReward()); ImGui::Text("\tEXP reward : %i", m_Mob->GetStats()->GetExpReward());
ImGui::EndTooltip(); ImGui::EndTooltip();
} else {
ImGui::BeginTooltip();
RenderLifeProgress(m_Mob->GetHealth() / m_Mob->GetStats()->GetMaxLife());
ImGui::EndTooltip();
}
} }
} // namespace gui } // namespace gui

View File

@@ -7,9 +7,18 @@ namespace gui {
SummonMenu::SummonMenu(client::Client* client) : GuiWidget(client), m_MenuOpened(true) { SummonMenu::SummonMenu(client::Client* client) : GuiWidget(client), m_MenuOpened(true) {
m_Values.fill(0); m_Values.fill(0);
SetCooldown(10);
}
void SummonMenu::SetCooldown(float cooldown) {
m_LastCooldown = cooldown;
m_Cooldown = cooldown;
} }
void SummonMenu::Render() { void SummonMenu::Render() {
if (m_Cooldown > 0)
m_Cooldown = std::max(0.0f, m_Cooldown - ImGui::GetIO().DeltaTime);
if (m_MenuOpened) { if (m_MenuOpened) {
ImGui::Begin("Summon", &m_MenuOpened); ImGui::Begin("Summon", &m_MenuOpened);
ImTextureID my_tex_id = ImGui::GetIO().Fonts->TexID; ImTextureID my_tex_id = ImGui::GetIO().Fonts->TexID;
@@ -48,7 +57,9 @@ void SummonMenu::Render() {
ImGui::PopID(); ImGui::PopID();
} }
ImGui::PopItemWidth(); ImGui::PopItemWidth();
if (ImGui::Button("Send")) { if (m_Cooldown > 0) {
ImGui::ProgressBar((m_LastCooldown - m_Cooldown) / m_LastCooldown, {}, std::string{ std::to_string((int)m_Cooldown + 1) + "s" }.c_str());
} else if (ImGui::Button("Send")) {
std::vector<protocol::MobSend> mobSent; std::vector<protocol::MobSend> mobSent;
protocol::MobSend mobSend; protocol::MobSend mobSend;
for (int i = 0; i < m_MobTypeCount; i++) { for (int i = 0; i < m_MobTypeCount; i++) {
@@ -59,8 +70,11 @@ void SummonMenu::Render() {
mobSent.push_back(mobSend); mobSent.push_back(mobSend);
} }
} }
if (mobSent.size() > 0) {
m_Client->SendMobs(mobSent); m_Client->SendMobs(mobSent);
m_Values.fill(0); m_Values.fill(0);
SetCooldown(10);
}
} }
ImGui::End(); ImGui::End();
} }

View File

@@ -27,7 +27,7 @@ void TowerPlacePopup::Render() {
ImGui::BeginChild(std::to_string(i).c_str(), ImVec2(m_TowerPopupTileWidth, m_TowerPopupTileHeight), true); ImGui::BeginChild(std::to_string(i).c_str(), ImVec2(m_TowerPopupTileWidth, m_TowerPopupTileHeight), true);
ImGui::Text(towerInfo.GetName().c_str()); ImGui::Text("%s", towerInfo.GetName().c_str());
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetCursorPosX(m_TowerPopupTileWidth - 10 - ImGui::CalcTextSize("(?)").x); ImGui::SetCursorPosX(m_TowerPopupTileWidth - 10 - ImGui::CalcTextSize("(?)").x);
@@ -35,7 +35,7 @@ void TowerPlacePopup::Render() {
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::Text(towerInfo.GetDescription().c_str()); ImGui::Text("%s", towerInfo.GetDescription().c_str());
ImGui::EndTooltip(); ImGui::EndTooltip();
} }

View File

@@ -0,0 +1,100 @@
#include "render/gui/TowerUpgradePopup.h"
#include "render/gui/imgui/imgui.h"
#include "game/Towers.h"
#include "game/client/Client.h"
namespace td {
namespace gui {
TowerUpgradePopup::TowerUpgradePopup(client::Client* client) : GuiWidget(client), m_ShouldBeClosed(false), m_Opened(false) {
}
void TowerUpgradePopup::SetClickPos(const Vec2f& worldPos) {
m_ClickWorldPos = worldPos;
}
bool TowerUpgradePopup::IsPopupOpened() {
return m_Opened;
}
void TowerUpgradePopup::Render() {
if (ImGui::BeginPopup("TowerUpgrade")) {
ImGui::BeginChild("TowerUpgradePopupChild", { 450, 350 });
if (m_ShouldBeClosed) {
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
return;
}
game::TowerPtr tower = m_Client->GetGame().GetWorld().GetTower(m_ClickWorldPos);
if (tower == nullptr) {
ImGui::EndPopup();
return;
}
ImGui::Text("Tower : %s", game::TowerFactory::GetTowerName(tower->GetType()).c_str());
for (int y = 0; y < 3; y++) { // path: 0 -> top 1 -> middle 2 -> bottom
for (int x = 0; x < 4; x++) { // level: 1, 2, 3, 4
if (x > 0)
ImGui::SameLine();
std::uint8_t currentLevel = x + 1;
game::TowerPath currentPath = game::TowerPath(y);
const game::TowerStats* towerStats = game::GetTowerStats(tower->GetType(), { currentLevel, currentPath });
game::TowerPath towerPath = tower->GetLevel().GetPath();
bool disabled = towerStats == nullptr;
int towerLevel = tower->GetLevel().GetLevel();
bool alreadyUpgraded = currentLevel <= towerLevel;
bool canUpgrade = (towerLevel + 1) == currentLevel;
if (canUpgrade && towerPath != game::TowerPath::Base) {
if (currentPath != towerPath) {
canUpgrade = false;
}
}
ImGui::PushID(x * 4 + y);
if (disabled) {
ImGui::BeginDisabled();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::Button("", ImVec2(100, 100));
ImGui::PopStyleColor();
ImGui::EndDisabled();
} else if (alreadyUpgraded) {
ImGui::BeginDisabled();
ImGui::Button("Already", ImVec2(100, 100));
ImGui::EndDisabled();
} else if (canUpgrade) {
if (ImGui::Button("Upgrade", ImVec2(100, 100))) {
m_Client->UpgradeTower(tower->GetID(), { currentLevel, currentPath });
}
} else {
ImGui::BeginDisabled();
ImGui::Button("Locked", ImVec2(100, 100));
ImGui::EndDisabled();
}
ImGui::PopID();
}
}
ImGui::EndChild();
ImGui::EndPopup();
m_Opened = true;
return;
}
m_Opened = false;
}
} // namespace gui
} // namespace td

View File

@@ -1,5 +1,7 @@
#include "render/gui/UpdateMenu.h" #include "render/gui/UpdateMenu.h"
#include "updater/Updater.h"
#include "render/gui/imgui/imgui.h" #include "render/gui/imgui/imgui.h"
#include <chrono> #include <chrono>
@@ -7,10 +9,12 @@
namespace td { namespace td {
namespace gui { namespace gui {
UpdateMenu::UpdateMenu(client::Client* client) : GuiWidget(client), m_Opened(true) { UpdateMenu::UpdateMenu(client::Client* client) : GuiWidget(client), m_Opened(true), m_Updater(std::make_unique<utils::Updater>()) {
CheckUpdates(); CheckUpdates();
} }
UpdateMenu::~UpdateMenu() {}
void UpdateMenu::Render() { void UpdateMenu::Render() {
RenderErrorPopup(); RenderErrorPopup();
if (m_Opened) { if (m_Opened) {
@@ -20,40 +24,40 @@ void UpdateMenu::Render() {
bool updateAvailable = m_UpdateAvailable.get(); bool updateAvailable = m_UpdateAvailable.get();
if (updateAvailable) { if (updateAvailable) {
if (m_Updater.IsFileWrited()) { if (m_Updater->IsFileWrited()) {
ImGui::Text("The update is now installed"); ImGui::Text("The update is now installed");
ImGui::Text("The game needs to be restarted"); ImGui::Text("The game needs to be restarted");
} else if (m_Updater.IsDownloadComplete()) { } else if (m_Updater->IsDownloadComplete()) {
ImGui::Text("Download done!"); ImGui::Text("Download done!");
if (ImGui::Button("Install")) { if (ImGui::Button("Install")) {
if (!m_Updater.WriteFile()) { if (!m_Updater->WriteFile()) {
m_Error = "Failed to write file !\n"; m_Error = "Failed to write file !\n";
ImGui::OpenPopup("UpdateError"); ImGui::OpenPopup("UpdateError");
} }
} }
if (ImGui::Button("Cancel")) { if (ImGui::Button("Cancel")) {
m_Updater.CancelDownload(); m_Updater->CancelDownload();
m_Updater.ClearCache(); m_Updater->ClearCache();
} }
} else { } else {
if (m_Updater.GetDownloadProgress() > 0) { if (m_Updater->GetDownloadProgress() > 0) {
ImGui::Text("Downloading ..."); ImGui::Text("Downloading ...");
ImGui::ProgressBar(m_Updater.GetDownloadProgress()); ImGui::ProgressBar(m_Updater->GetDownloadProgress());
if (ImGui::Button("Cancel")) { if (ImGui::Button("Cancel")) {
m_Updater.CancelDownload(); m_Updater->CancelDownload();
} }
} else { } else {
ImGui::Text("An update is available!"); ImGui::Text("An update is available!");
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Current version : %s", m_Updater.GetCurrentVersion().c_str()); ImGui::Text("Current version : %s", m_Updater->GetCurrentVersion().c_str());
ImGui::Text("Last version : %s", m_Updater.GetLastVersion().c_str()); ImGui::Text("Last version : %s", m_Updater->GetLastVersion().c_str());
bool canDownloadFile = m_Updater.CanUpdate(); bool canDownloadFile = m_Updater->CanUpdate();
if (!canDownloadFile) ImGui::BeginDisabled(); if (!canDownloadFile) ImGui::BeginDisabled();
if (ImGui::Button("Download")) { if (ImGui::Button("Download")) {
m_Updater.DownloadUpdate(); m_Updater->DownloadUpdate();
} }
if (!canDownloadFile) ImGui::EndDisabled(); if (!canDownloadFile) ImGui::EndDisabled();
@@ -67,8 +71,8 @@ void UpdateMenu::Render() {
} else { } else {
ImGui::Text("No update available!"); ImGui::Text("No update available!");
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Current version : %s", m_Updater.GetCurrentVersion().c_str()); ImGui::Text("Current version : %s", m_Updater->GetCurrentVersion().c_str());
ImGui::Text("Last version : %s", m_Updater.GetLastVersion().c_str()); ImGui::Text("Last version : %s", m_Updater->GetLastVersion().c_str());
} }
} else { } else {
ImGui::Text("Checking updates ..."); ImGui::Text("Checking updates ...");
@@ -89,7 +93,7 @@ bool UpdateMenu::IsUpdateChecked() {
} }
void UpdateMenu::CheckUpdates() { void UpdateMenu::CheckUpdates() {
m_UpdateAvailable = std::async(std::launch::async, [&]() { return m_Updater.CheckUpdate();}); m_UpdateAvailable = std::async(std::launch::async, [&]() { return m_Updater->CheckUpdate();});
} }
} // namespace gui } // namespace gui

View File

@@ -10,15 +10,17 @@ namespace render {
namespace WorldLoader { namespace WorldLoader {
const static int VERTEX_SIZE = 3;
GL::VertexArray LoadMobModel() { GL::VertexArray LoadMobModel() {
std::vector<float> positions = { std::vector<float> positions = {
-0.5, -0.5, -0.5, 0, -0.5,
0.5, -0.5, 0.5, 0, -0.5,
-0.5, 0.5, -0.5, 0, 0.5,
0.5, -0.5, 0.5, 0, -0.5,
-0.5, 0.5, -0.5, 0, 0.5,
0.5, 0.5 0.5, 0, 0.5
}; };
float yellowFloat; float yellowFloat;
@@ -35,8 +37,8 @@ GL::VertexArray LoadMobModel() {
yellowFloat yellowFloat
}; };
GL::VertexBuffer positionVBO(positions, 2); GL::VertexBuffer positionVBO(positions, VERTEX_SIZE);
positionVBO.AddVertexAttribPointer(0, 2, 0); positionVBO.AddVertexAttribPointer(0, VERTEX_SIZE, 0);
GL::VertexBuffer colorVBO(colors, 1); GL::VertexBuffer colorVBO(colors, 1);
colorVBO.AddVertexAttribPointer(1, 1, 0); colorVBO.AddVertexAttribPointer(1, 1, 0);
@@ -69,16 +71,16 @@ GL::VertexArray LoadWorldModel(const td::game::World* world) {
continue; continue;
positions.insert(positions.end(), { positions.insert(positions.end(), {
static_cast<float>(chunkX + tileX), static_cast<float>(chunkY + tileY), static_cast<float>(chunkX + tileX), 0, static_cast<float>(chunkY + tileY),
static_cast<float>(chunkX + tileX + 1), static_cast<float>(chunkY + tileY), static_cast<float>(chunkX + tileX + 1), 0, static_cast<float>(chunkY + tileY),
static_cast<float>(chunkX + tileX), static_cast<float>(chunkY + tileY + 1), static_cast<float>(chunkX + tileX), 0, static_cast<float>(chunkY + tileY + 1),
static_cast<float>(chunkX + tileX + 1), static_cast<float>(chunkY + tileY), static_cast<float>(chunkX + tileX + 1), 0, static_cast<float>(chunkY + tileY),
static_cast<float>(chunkX + tileX), static_cast<float>(chunkY + tileY + 1), static_cast<float>(chunkX + tileX), 0, static_cast<float>(chunkY + tileY + 1),
static_cast<float>(chunkX + tileX + 1), static_cast<float>(chunkY + tileY + 1), static_cast<float>(chunkX + tileX + 1), 0, static_cast<float>(chunkY + tileY + 1)
}); });
const td::game::Color* tileColor = world->GetTileColor(tile); const td::Color* tileColor = world->GetTileColor(tile);
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
int color = 255; int color = 255;
@@ -101,13 +103,13 @@ GL::VertexArray LoadWorldModel(const td::game::World* world) {
float fromY = spawn.GetTopLeft().GetY(), toY = spawn.GetBottomRight().GetY(); float fromY = spawn.GetTopLeft().GetY(), toY = spawn.GetBottomRight().GetY();
positions.insert(positions.end(), { positions.insert(positions.end(), {
fromX, fromY, fromX, 0, fromY,
fromX, toY, fromX, 0, toY,
toX, fromY, toX, 0, fromY,
toX, toY, toX, 0, toY,
fromX, toY, fromX, 0, toY,
toX, fromY, toX, 0, fromY,
}); });
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
@@ -129,13 +131,13 @@ GL::VertexArray LoadWorldModel(const td::game::World* world) {
float fromY = castle.GetTopLeft().GetY(), toY = castle.GetBottomRight().GetY(); float fromY = castle.GetTopLeft().GetY(), toY = castle.GetBottomRight().GetY();
positions.insert(positions.end(), { positions.insert(positions.end(), {
fromX, fromY, fromX, 0, fromY,
fromX, toY, fromX, 0, toY,
toX, fromY, toX, 0, fromY,
toX, toY, toX, 0, toY,
fromX, toY, fromX, 0, toY,
toX, fromY, toX, 0, fromY,
}); });
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
@@ -151,12 +153,12 @@ GL::VertexArray LoadWorldModel(const td::game::World* world) {
} }
} }
GL::VertexBuffer positionVBO(positions, 2); GL::VertexBuffer positionVBO(positions, VERTEX_SIZE);
positionVBO.AddVertexAttribPointer(0, 2, 0); positionVBO.AddVertexAttribPointer(0, VERTEX_SIZE, 0);
GL::VertexBuffer colorVBO(colors, 1); GL::VertexBuffer colorVBO(colors, 1);
colorVBO.AddVertexAttribPointer(1, 1, 0); colorVBO.AddVertexAttribPointer(1, 1, 0);
GL::VertexArray worldVao(positions.size() / 2); // each pos = 2 vertecies GL::VertexArray worldVao(positions.size() / VERTEX_SIZE); // each pos = 3 vertecies
worldVao.Bind(); worldVao.Bind();
worldVao.BindVertexBuffer(positionVBO); worldVao.BindVertexBuffer(positionVBO);
worldVao.BindVertexBuffer(colorVBO); worldVao.BindVertexBuffer(colorVBO);
@@ -166,13 +168,13 @@ GL::VertexArray LoadWorldModel(const td::game::World* world) {
GL::VertexArray LoadTileSelectModel() { GL::VertexArray LoadTileSelectModel() {
std::vector<float> positions = { std::vector<float> positions = {
0, 0, 0, 0, 0,
1, 0, 1, 0, 0,
0, 1, 0, 0, 1,
1, 0, 1, 0, 0,
0, 1, 0, 0, 1,
1, 1 1, 0, 1
}; };
int color = 255 << 24 | 255 << 16 | 255 << 8 | 150; int color = 255 << 24 | 255 << 16 | 255 << 8 | 150;
@@ -182,8 +184,8 @@ GL::VertexArray LoadTileSelectModel() {
std::vector<float> colors(6, colorFloat); std::vector<float> colors(6, colorFloat);
GL::VertexBuffer positionVBO(positions, 2); GL::VertexBuffer positionVBO(positions, VERTEX_SIZE);
positionVBO.AddVertexAttribPointer(0, 2, 0); positionVBO.AddVertexAttribPointer(0, VERTEX_SIZE, 0);
GL::VertexBuffer colorVBO(colors, 1); GL::VertexBuffer colorVBO(colors, 1);
colorVBO.AddVertexAttribPointer(1, 1, 0); colorVBO.AddVertexAttribPointer(1, 1, 0);
@@ -216,13 +218,13 @@ RenderData LoadTowerModel(game::TowerPtr tower) {
towerDY = tower->GetCenterY() + 2.5f; towerDY = tower->GetCenterY() + 2.5f;
} }
std::vector<float> positions = { std::vector<float> positions = {
towerX, towerY, towerX, 0, towerY,
towerDX, towerY, towerDX, 0, towerY,
towerX, towerDY, towerX, 0, towerDY,
towerDX, towerY, towerDX, 0, towerY,
towerX, towerDY, towerX, 0, towerDY,
towerDX, towerDY towerDX, 0, towerDY
}; };
renderData.positions = positions; renderData.positions = positions;

View File

@@ -9,24 +9,18 @@ R"(#version 300 es
precision mediump float; precision mediump float;
layout(location = 0) in vec2 position; layout(location = 0) in vec3 position;
layout(location = 1) in int color; layout(location = 1) in int color;
uniform vec2 camPos; uniform mat4 viewMatrix;
uniform float zoom; uniform mat4 projectionMatrix;
uniform float aspectRatio; uniform vec3 modelPosition;
uniform vec2 translation;
uniform float isometricView;
flat out int pass_color; flat out int pass_color;
void main(void){ void main(void){
float modelX = position.x + translation.x;
float modelY = position.y + translation.y;
float x = (modelX - camPos.x - (modelY - camPos.y) * isometricView) / aspectRatio * zoom;
float y = ((0.5 * (modelX - camPos.x) + 0.5 * (modelY - camPos.y)) * isometricView + (modelY - camPos.y) * (1.0 - isometricView)) * zoom;
pass_color = color; pass_color = color;
gl_Position = vec4(x, -y, 0.0, 1.0); gl_Position = projectionMatrix * viewMatrix * vec4(position + modelPosition, 1.0);
} }
)"; )";
@@ -39,13 +33,16 @@ flat in int pass_color;
out vec4 out_color; out vec4 out_color;
uniform vec3 ColorEffect;
void main(void){ void main(void){
float r = float(pass_color >> 24 & 0xFF) / 255.0; float r = float(pass_color >> 24 & 0xFF) / 255.0;
float g = float(pass_color >> 16 & 0xFF) / 255.0; float g = float(pass_color >> 16 & 0xFF) / 255.0;
float b = float(pass_color >> 8 & 0xFF) / 255.0; float b = float(pass_color >> 8 & 0xFF) / 255.0;
float a = float(pass_color & 0xFF) / 255.0; float a = float(pass_color & 0xFF) / 255.0;
out_color = vec4(r, g, b, a); vec3 intermediate_color = vec3(r, g, b) * ColorEffect;
out_color = vec4(intermediate_color, a);
} }
)"; )";
@@ -53,24 +50,18 @@ void main(void){
static const char vertexSource[] = R"( static const char vertexSource[] = R"(
#version 330 #version 330
layout(location = 0) in vec2 position; layout(location = 0) in vec3 position;
layout(location = 1) in int color; layout(location = 1) in int color;
uniform vec2 camPos; uniform mat4 viewMatrix;
uniform float zoom; uniform mat4 projectionMatrix;
uniform float aspectRatio; uniform vec3 modelPosition;
uniform vec2 translation;
uniform float isometricView;
flat out int pass_color; flat out int pass_color;
void main(void){ void main(void){
float modelX = position.x + translation.x;
float modelY = position.y + translation.y;
float x = (modelX - camPos.x - (modelY - camPos.y) * isometricView) / aspectRatio * zoom;
float y = ((0.5 * (modelX - camPos.x) + 0.5 * (modelY - camPos.y)) * isometricView + (modelY - camPos.y) * (1.0 - isometricView)) * zoom;
pass_color = color; pass_color = color;
gl_Position = vec4(x, -y, 0.0, 1.0); gl_Position = projectionMatrix * viewMatrix * vec4(position + modelPosition, 1.0);
} }
)"; )";
@@ -81,13 +72,16 @@ flat in int pass_color;
out vec4 out_color; out vec4 out_color;
uniform vec3 ColorEffect;
void main(void){ void main(void){
float r = float(pass_color >> 24 & 0xFF) / 255.0; float r = float(pass_color >> 24 & 0xFF) / 255.0;
float g = float(pass_color >> 16 & 0xFF) / 255.0; float g = float(pass_color >> 16 & 0xFF) / 255.0;
float b = float(pass_color >> 8 & 0xFF) / 255.0; float b = float(pass_color >> 8 & 0xFF) / 255.0;
float a = float(pass_color & 0xFF) / 255.0; float a = float(pass_color & 0xFF) / 255.0;
out_color = vec4(r, g, b, a); vec3 intermediate_color = vec3(r, g, b) * ColorEffect;
out_color = vec4(intermediate_color, a);
} }
)"; )";
@@ -100,29 +94,27 @@ void EntityShader::LoadShader() {
} }
void EntityShader::GetAllUniformLocation() { void EntityShader::GetAllUniformLocation() {
m_LocationAspectRatio = static_cast<unsigned int>(GetUniformLocation("aspectRatio")); m_LocationColorEffect = static_cast<unsigned int>(GetUniformLocation("ColorEffect"));
m_LocationZoom = static_cast<unsigned int>(GetUniformLocation("zoom")); m_LocationViewMatrix = static_cast<unsigned int>(GetUniformLocation("viewMatrix"));
m_LocationCam = static_cast<unsigned int>(GetUniformLocation("camPos")); m_LocationPosition = static_cast<unsigned int>(GetUniformLocation("modelPosition"));
m_LocationTranslation = static_cast<unsigned int>(GetUniformLocation("translation")); m_LocationProjectionMatrix = static_cast<unsigned int>(GetUniformLocation("projectionMatrix"));
m_LocationViewtype = static_cast<unsigned int>(GetUniformLocation("isometricView"));
} }
void EntityShader::SetCamPos(const Vec2f& camPos) { void EntityShader::SetColorEffect(const Vec3f& color) {
LoadVector(m_LocationCam, camPos); LoadVector(m_LocationColorEffect, color);
}
void EntityShader::SetZoom(float zoom) {
LoadFloat(m_LocationZoom, zoom);
}
void EntityShader::SetAspectRatio(float aspectRatio) {
LoadFloat(m_LocationAspectRatio, aspectRatio);
}
void EntityShader::SetModelPos(const Vec2f& modelPos) {
LoadVector(m_LocationTranslation, modelPos);
}
void EntityShader::SetIsometricView(float isometric) {
LoadFloat(m_LocationViewtype, isometric);
} }
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 {
LoadVector(m_LocationPosition, pos);
}
} // namespace shader } // namespace shader
} // namespace td } // namespace td

View File

@@ -67,6 +67,10 @@ void ShaderProgram::LoadBoolean(unsigned int location, bool value) const {
glUniform1i(static_cast<GLint>(location), value); glUniform1i(static_cast<GLint>(location), value);
} }
void ShaderProgram::LoadMat4(unsigned int location, const Mat4f& mat) const {
glUniformMatrix4fv(static_cast<GLint>(location), 1, false, reinterpret_cast<const float*>(&mat));
}
void ShaderProgram::CleanUp() const { void ShaderProgram::CleanUp() const {
Stop(); Stop();
glDetachShader(m_ProgramID, m_VertexShaderID); glDetachShader(m_ProgramID, m_VertexShaderID);
@@ -118,6 +122,12 @@ unsigned int ShaderProgram::LoadShader(const std::string& source, GLenum type) {
utils::LOGE("Could not compile shader !"); utils::LOGE("Could not compile shader !");
utils::LOGE(shaderError.data()); utils::LOGE(shaderError.data());
utils::LOGD(utils::format("\nShader source : \n"
"------------------------------------------------------------------------------------------------------------------------------------\n"
"%s\n"
"------------------------------------------------------------------------------------------------------------------------------------\n"
, source.c_str()));
} }
return shaderID; return shaderID;
} }

View File

@@ -3,27 +3,25 @@
namespace td { namespace td {
namespace shader { namespace shader {
// TODO: GLES Shaders
#ifdef __ANDROID__ #ifdef __ANDROID__
static const char vertexSource[] = static const char vertexSource[] =
R"(#version 300 es R"(#version 300 es
precision mediump float; precision mediump float;
layout(location = 0) in vec2 position; layout(location = 0) in vec3 position;
layout(location = 1) in int color; layout(location = 1) in int color;
uniform vec2 camPos; uniform mat4 viewMatrix;
uniform float zoom; uniform mat4 projectionMatrix;
uniform float aspectRatio;
uniform float isometricView;
flat out int pass_color; flat out int pass_color;
void main(void){ void main(void){
float x = (position.x - camPos.x - (position.y - camPos.y) * isometricView) / aspectRatio * zoom;
float y = ((0.5 * (position.x - camPos.x) + 0.5 * (position.y - camPos.y)) * isometricView + (position.y - camPos.y) * (1.0 - isometricView)) * zoom;
pass_color = color; pass_color = color;
gl_Position = vec4(x, -y, 0.0, 1.0); gl_Position = projectionMatrix * viewMatrix * vec4(position, 1.0);
} }
)"; )";
@@ -50,21 +48,17 @@ void main(void){
static const char vertexSource[] = R"( static const char vertexSource[] = R"(
#version 330 #version 330
layout(location = 0) in vec2 position; layout(location = 0) in vec3 position;
layout(location = 1) in int color; layout(location = 1) in int color;
uniform vec2 camPos; uniform mat4 viewMatrix;
uniform float zoom; uniform mat4 projectionMatrix;
uniform float aspectRatio;
uniform float isometricView;
flat out int pass_color; flat out int pass_color;
void main(void){ void main(void){
float x = (position.x - camPos.x - (position.y - camPos.y) * isometricView) / aspectRatio * zoom;
float y = ((0.5 * (position.x - camPos.x) + 0.5 * (position.y - camPos.y)) * isometricView + (position.y - camPos.y) * (1.0 - isometricView)) * zoom;
pass_color = color; pass_color = color;
gl_Position = vec4(x, -y, 0.0, 1.0); gl_Position = projectionMatrix * viewMatrix * vec4(position, 1.0);
} }
)"; )";
@@ -94,23 +88,16 @@ void WorldShader::LoadShader() {
} }
void WorldShader::GetAllUniformLocation() { void WorldShader::GetAllUniformLocation() {
m_LocationAspectRatio = static_cast<unsigned int>(GetUniformLocation("aspectRatio")); m_LocationProjection = static_cast<unsigned int>(GetUniformLocation("projectionMatrix"));
m_LocationZoom = static_cast<unsigned int>(GetUniformLocation("zoom")); m_LocationView = static_cast<unsigned int>(GetUniformLocation("viewMatrix"));
m_LocationCam = static_cast<unsigned int>(GetUniformLocation("camPos"));
m_LocationViewtype = static_cast<unsigned int>(GetUniformLocation("isometricView"));
} }
void WorldShader::SetCamPos(const Vec2f& camPos) { void WorldShader::SetProjectionMatrix(const Mat4f& proj) const {
LoadVector(m_LocationCam, camPos); LoadMat4(m_LocationProjection, proj);
} }
void WorldShader::SetZoom(float zoom) {
LoadFloat(m_LocationZoom, zoom); void WorldShader::SetViewMatrix(const Mat4f& view) const {
} LoadMat4(m_LocationView, view);
void WorldShader::SetAspectRatio(float aspectRatio) {
LoadFloat(m_LocationAspectRatio, aspectRatio);
}
void WorldShader::SetIsometricView(float isometric) {
LoadFloat(m_LocationViewtype, isometric);
} }
} // namespace shader } // namespace shader

View File

@@ -6,14 +6,14 @@ add_requires("libsdl >= 2", "zlib", "glew")
target("TowerDefense") target("TowerDefense")
set_kind("binary") set_kind("binary")
add_includedirs("include") add_includedirs("include")
add_files("src/*.cpp", "src/*/*.cpp", "src/*/*/*.cpp", "src/*/*/*/*.cpp") add_files("src/**.cpp")
add_cxflags("-pthread") add_cxflags("-pthread")
add_links("pthread") add_links("pthread")
set_languages("c++17") set_languages("c++17")
add_packages("zlib", "libsdl", "glew", "opengl", "glm") add_packages("zlib", "libsdl", "glew", "opengl")
if is_os("windows") then if is_os("windows") then
add_links("ws2_32") -- link network stuff add_links("ws2_32") -- link network stuff
@@ -28,7 +28,7 @@ target("TowerDefense")
set_warnings("all", "error") set_warnings("all", "error")
set_optimize("smallest") set_optimize("fastest")
else -- debug stuff else -- debug stuff
if is_os("linux") then if is_os("linux") then
@@ -37,7 +37,7 @@ target("TowerDefense")
if is_os("windows") then if is_os("windows") then
add_links("dbghelp", "psapi", "kernel32", "msvcr90") add_links("dbghelp", "psapi", "kernel32", "msvcr90")
end 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 -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wswitch-default -Wundef -Wno-unused") add_cxflags("-pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=1 -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wswitch-default -Wundef -Wno-unused")
end end