Compare commits
8 Commits
editor
...
45c9e5180f
| Author | SHA1 | Date | |
|---|---|---|---|
|
45c9e5180f
|
|||
|
19ebe7b64f
|
|||
|
d9baf7c5ef
|
|||
|
701dd6b120
|
|||
|
2225151f72
|
|||
|
aef0cf4d95
|
|||
|
550ff3aeec
|
|||
|
127fa1fcb8
|
1721
assets/zombie.fbx
Normal file
1721
assets/zombie.fbx
Normal file
File diff suppressed because it is too large
Load Diff
BIN
assets/zombie.png
Normal file
BIN
assets/zombie.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 994 B |
@@ -12,6 +12,7 @@ class GameState : public ClientState {
|
|||||||
game::WorldPtr m_World;
|
game::WorldPtr m_World;
|
||||||
sim::ClientSimulation m_Simulation;
|
sim::ClientSimulation m_Simulation;
|
||||||
float m_CurrentLerp;
|
float m_CurrentLerp;
|
||||||
|
float m_ElapsedTime;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GameState(Client& a_Client, const game::WorldPtr& a_World, std::uint64_t a_StepTime, const std::vector<protocol::LockStep> a_FirstSteps);
|
GameState(Client& a_Client, const game::WorldPtr& a_World, std::uint64_t a_StepTime, const std::vector<protocol::LockStep> a_FirstSteps);
|
||||||
@@ -23,6 +24,10 @@ class GameState : public ClientState {
|
|||||||
return m_CurrentLerp;
|
return m_CurrentLerp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float GetElapsedTime() const {
|
||||||
|
return m_ElapsedTime;
|
||||||
|
}
|
||||||
|
|
||||||
game::WorldPtr GetWorld() const {
|
game::WorldPtr GetWorld() const {
|
||||||
return m_World;
|
return m_World;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,6 +183,51 @@ T Lerp(T v0, T v1, T t) {
|
|||||||
|
|
||||||
} // namespace maths
|
} // namespace maths
|
||||||
|
|
||||||
|
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.z };
|
||||||
|
}
|
||||||
|
|
||||||
|
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.z, vect.w + other.w };
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Vec4<T> operator- (const Vec4<T>& vect, const Vec4<T>& other) {
|
||||||
|
return vect + (-other);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
sp::DataBuffer& operator<<(sp::DataBuffer& a_Buffer, const Vec2<T>& a_Vec) {
|
sp::DataBuffer& operator<<(sp::DataBuffer& a_Buffer, const Vec2<T>& a_Vec) {
|
||||||
return a_Buffer << a_Vec.x << a_Vec.y;
|
return a_Buffer << a_Vec.x << a_Vec.y;
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ class DebugWorldState : public DisplayState {
|
|||||||
std::vector<std::unique_ptr<client::Client>> m_FakeClients;
|
std::vector<std::unique_ptr<client::Client>> m_FakeClients;
|
||||||
std::shared_ptr<server::FakeSocket> m_ServerSocket;
|
std::shared_ptr<server::FakeSocket> m_ServerSocket;
|
||||||
|
|
||||||
|
unsigned int m_PlaySpeed = 1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DebugWorldState(Display& a_Display);
|
DebugWorldState(Display& a_Display);
|
||||||
~DebugWorldState();
|
~DebugWorldState();
|
||||||
|
|||||||
@@ -1,127 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <td/display/DisplayState.h>
|
|
||||||
|
|
||||||
#include <imgui_node_editor.h>
|
|
||||||
|
|
||||||
namespace ed = ax::NodeEditor;
|
|
||||||
|
|
||||||
namespace td {
|
|
||||||
|
|
||||||
class NodeEditorState : public DisplayState {
|
|
||||||
public:
|
|
||||||
enum class PinType {
|
|
||||||
Flow,
|
|
||||||
Bool,
|
|
||||||
Int,
|
|
||||||
Float,
|
|
||||||
String,
|
|
||||||
Object,
|
|
||||||
Function,
|
|
||||||
Delegate,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class PinKind { Output, Input };
|
|
||||||
|
|
||||||
enum class NodeType { Blueprint, Simple, Tree, Comment, Houdini };
|
|
||||||
|
|
||||||
struct Pin;
|
|
||||||
|
|
||||||
struct Node {
|
|
||||||
ed::NodeId ID;
|
|
||||||
std::string Name;
|
|
||||||
std::vector<Pin> Inputs;
|
|
||||||
std::vector<Pin> Outputs;
|
|
||||||
ImColor Color;
|
|
||||||
NodeType Type;
|
|
||||||
ImVec2 Size;
|
|
||||||
|
|
||||||
std::string State;
|
|
||||||
std::string SavedState;
|
|
||||||
|
|
||||||
Node(int id, const char* name, ImColor color = ImColor(255, 255, 255)) :
|
|
||||||
ID(id), Name(name), Color(color), Type(NodeType::Blueprint), Size(0, 0) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Pin {
|
|
||||||
ed::PinId ID;
|
|
||||||
::td::NodeEditorState::Node* Node;
|
|
||||||
std::string Name;
|
|
||||||
PinType Type;
|
|
||||||
PinKind Kind;
|
|
||||||
|
|
||||||
Pin(int id, const char* name, PinType type) : ID(id), Node(nullptr), Name(name), Type(type), Kind(PinKind::Input) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Link {
|
|
||||||
ed::LinkId ID;
|
|
||||||
|
|
||||||
ed::PinId StartPinID;
|
|
||||||
ed::PinId EndPinID;
|
|
||||||
|
|
||||||
ImColor Color;
|
|
||||||
|
|
||||||
Link(ed::LinkId id, ed::PinId startPinId, ed::PinId endPinId) :
|
|
||||||
ID(id), StartPinID(startPinId), EndPinID(endPinId), Color(255, 255, 255) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NodeIdLess {
|
|
||||||
bool operator()(const ed::NodeId& lhs, const ed::NodeId& rhs) const {
|
|
||||||
return lhs.AsPointer() < rhs.AsPointer();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int m_NextId = 1;
|
|
||||||
const int m_PinIconSize = 24;
|
|
||||||
std::vector<Node> m_Nodes;
|
|
||||||
std::vector<Link> m_Links;
|
|
||||||
ImTextureID m_HeaderBackground = 0;
|
|
||||||
ImTextureID m_SaveIcon = 0;
|
|
||||||
ImTextureID m_RestoreIcon = 0;
|
|
||||||
const float m_TouchTime = 1.0f;
|
|
||||||
std::map<ed::NodeId, float, NodeIdLess> m_NodeTouchTime;
|
|
||||||
bool m_ShowOrdinals = false;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
NodeEditorState(Display& a_Display);
|
|
||||||
~NodeEditorState();
|
|
||||||
|
|
||||||
virtual void Update(float a_Delta) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
int GetNextId();
|
|
||||||
ed::LinkId GetNextLinkId();
|
|
||||||
void TouchNode(ed::NodeId id);
|
|
||||||
float GetTouchProgress(ed::NodeId id);
|
|
||||||
void UpdateTouch();
|
|
||||||
Node* FindNode(ed::NodeId id);
|
|
||||||
Link* FindLink(ed::LinkId id);
|
|
||||||
Pin* FindPin(ed::PinId id);
|
|
||||||
bool IsPinLinked(ed::PinId id);
|
|
||||||
bool CanCreateLink(Pin* a, Pin* b);
|
|
||||||
void BuildNode(Node* node);
|
|
||||||
Node* SpawnInputActionNode();
|
|
||||||
Node* SpawnBranchNode();
|
|
||||||
Node* SpawnDoNNode();
|
|
||||||
Node* SpawnOutputActionNode();
|
|
||||||
Node* SpawnPrintStringNode();
|
|
||||||
Node* SpawnMessageNode();
|
|
||||||
Node* SpawnSetTimerNode();
|
|
||||||
Node* SpawnLessNode();
|
|
||||||
Node* SpawnWeirdNode();
|
|
||||||
Node* SpawnTraceByChannelNode();
|
|
||||||
Node* SpawnTreeSequenceNode();
|
|
||||||
Node* SpawnTreeTaskNode();
|
|
||||||
Node* SpawnTreeTask2Node();
|
|
||||||
Node* SpawnComment();
|
|
||||||
Node* SpawnHoudiniTransformNode();
|
|
||||||
Node* SpawnHoudiniGroupNode();
|
|
||||||
void BuildNodes();
|
|
||||||
ImColor GetIconColor(PinType type);
|
|
||||||
void DrawPinIcon(const Pin& pin, bool connected, int alpha);
|
|
||||||
void ShowStyleEditor(bool* show = nullptr);
|
|
||||||
void ShowLeftPane(float paneWidth);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace td
|
|
||||||
@@ -35,6 +35,7 @@ class Camera {
|
|||||||
void UpdatePerspective(float a_AspectRatio);
|
void UpdatePerspective(float a_AspectRatio);
|
||||||
|
|
||||||
void SetCamPos(const Vec3f& a_NewPos);
|
void SetCamPos(const Vec3f& a_NewPos);
|
||||||
|
const Vec3f& GetCamPos() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace render
|
} // namespace render
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <td/misc/SlotGuard.h>
|
||||||
#include <td/render/Camera.h>
|
#include <td/render/Camera.h>
|
||||||
|
#include <td/render/loader/FbxLoader.h>
|
||||||
#include <td/render/loader/GLLoader.h>
|
#include <td/render/loader/GLLoader.h>
|
||||||
#include <td/render/shader/CameraShaderProgram.h>
|
#include <td/render/shader/CameraShaderProgram.h>
|
||||||
#include <td/misc/SlotGuard.h>
|
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace render {
|
namespace render {
|
||||||
@@ -15,6 +16,7 @@ class BasicRenderer {
|
|||||||
virtual ~BasicRenderer() {}
|
virtual ~BasicRenderer() {}
|
||||||
|
|
||||||
void Render(const GL::VertexArray& a_Vao);
|
void Render(const GL::VertexArray& a_Vao);
|
||||||
|
void Render(const Model& a_Model);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TShader>
|
template <typename TShader>
|
||||||
|
|||||||
19
include/td/render/loader/FbxLoader.h
Normal file
19
include/td/render/loader/FbxLoader.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <td/render/loader/GLLoader.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
|
||||||
|
struct Model {
|
||||||
|
std::vector<std::unique_ptr<GL::VertexArray>> m_Vaos;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace ModelLoader {
|
||||||
|
|
||||||
|
Model LoadModel(const std::string& fileName);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <td/render/loader/FbxLoader.h>
|
||||||
#include <td/render/Renderer.h>
|
#include <td/render/Renderer.h>
|
||||||
#include <td/render/shader/EntityShader.h>
|
#include <td/render/shader/EntityShader.h>
|
||||||
#include <td/game/World.h>
|
#include <td/game/World.h>
|
||||||
@@ -10,7 +11,7 @@ namespace render {
|
|||||||
class EntityRenderer : public Renderer<shader::EntityShader> {
|
class EntityRenderer : public Renderer<shader::EntityShader> {
|
||||||
private:
|
private:
|
||||||
game::WorldPtr m_World;
|
game::WorldPtr m_World;
|
||||||
std::unique_ptr<GL::VertexArray> m_EntityVao;
|
Model m_EntityModel;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EntityRenderer(Camera& a_Camera, const game::WorldPtr& a_World);
|
EntityRenderer(Camera& a_Camera, const game::WorldPtr& a_World);
|
||||||
|
|||||||
21
include/td/render/renderer/TimerRenderer.h
Normal file
21
include/td/render/renderer/TimerRenderer.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "client/state/GameState.h"
|
||||||
|
#include <td/render/Renderer.h>
|
||||||
|
#include <client/PlayerManager.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
class TimerRenderer : public BasicRenderer {
|
||||||
|
private:
|
||||||
|
const client::GameState& m_State;
|
||||||
|
public:
|
||||||
|
virtual void Render(float a_Lerp) override;
|
||||||
|
|
||||||
|
TimerRenderer(const client::GameState& a_State);
|
||||||
|
~TimerRenderer() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace render
|
||||||
|
} // namespace td
|
||||||
@@ -17,6 +17,9 @@ class WorldRenderer : public Renderer<shader::WorldShader> {
|
|||||||
virtual ~WorldRenderer();
|
virtual ~WorldRenderer();
|
||||||
|
|
||||||
virtual void Render(float a_Lerp) override;
|
virtual void Render(float a_Lerp) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void UpdateControls();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace render
|
} // namespace render
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
|
|
||||||
target("imgui-node-editor")
|
|
||||||
set_kind("static")
|
|
||||||
add_files("imgui-node-editor/**.cpp")
|
|
||||||
add_includedirs("imgui-node-editor", {public = true})
|
|
||||||
add_packages("imgui")
|
|
||||||
@@ -20,6 +20,7 @@ void GameState::Handle(const protocol::packets::LockStepResponsePacket& a_LockSt
|
|||||||
|
|
||||||
void GameState::Update(float a_Delta) {
|
void GameState::Update(float a_Delta) {
|
||||||
m_CurrentLerp = m_Simulation.Update(a_Delta);
|
m_CurrentLerp = m_Simulation.Update(a_Delta);
|
||||||
|
m_ElapsedTime += a_Delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace client
|
} // namespace client
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <td/display/state/NodeEditorState.h>
|
#include <td/display/state/MainMenuState.h>
|
||||||
#include <td/misc/Time.h>
|
#include <td/misc/Time.h>
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
// init GL context
|
// init GL context
|
||||||
td::Display display(1920, 1080, "Tower-Defense 2");
|
td::Display display(1920, 1080, "Tower-Defense 2");
|
||||||
|
|
||||||
display.ChangeState<td::NodeEditorState>();
|
display.ChangeState<td::MainMenuState>();
|
||||||
|
|
||||||
td::Timer timer;
|
td::Timer timer;
|
||||||
while (!display.IsCloseRequested()) {
|
while (!display.IsCloseRequested()) {
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ void GameState::Update(float a_Delta) {
|
|||||||
// TODO: don't make STEP_TIME constant
|
// TODO: don't make STEP_TIME constant
|
||||||
static const float stepTimeSecond = static_cast<float>(STEP_TIME) / 1000.0f;
|
static const float stepTimeSecond = static_cast<float>(STEP_TIME) / 1000.0f;
|
||||||
m_Time += a_Delta;
|
m_Time += a_Delta;
|
||||||
if (m_Time > stepTimeSecond) {
|
while (m_Time > stepTimeSecond) {
|
||||||
m_Time = std::fmod(m_Time, stepTimeSecond);
|
m_Time -= stepTimeSecond;
|
||||||
auto lockStepPacket = m_Simulation.Update();
|
auto lockStepPacket = m_Simulation.Update();
|
||||||
BroadcastPacket(lockStepPacket);
|
BroadcastPacket(lockStepPacket);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <td/protocol/packet/Packets.h>
|
#include <td/protocol/packet/Packets.h>
|
||||||
#include <td/render/renderer/EntityRenderer.h>
|
#include <td/render/renderer/EntityRenderer.h>
|
||||||
#include <td/render/renderer/PlayerListRenderer.h>
|
#include <td/render/renderer/PlayerListRenderer.h>
|
||||||
|
#include <td/render/renderer/TimerRenderer.h>
|
||||||
#include <td/render/renderer/TowerRenderer.h>
|
#include <td/render/renderer/TowerRenderer.h>
|
||||||
#include <td/render/renderer/WorldRenderer.h>
|
#include <td/render/renderer/WorldRenderer.h>
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ DebugWorldState::DebugWorldState(Display& a_Display) : DisplayState(a_Display) {
|
|||||||
m_Renderer.AddRenderer<render::WorldRenderer>(m_Camera, clientWorld);
|
m_Renderer.AddRenderer<render::WorldRenderer>(m_Camera, clientWorld);
|
||||||
m_Renderer.AddRenderer<render::EntityRenderer>(m_Camera, clientWorld);
|
m_Renderer.AddRenderer<render::EntityRenderer>(m_Camera, clientWorld);
|
||||||
m_Renderer.AddRenderer<render::TowerRenderer>(m_Camera, clientWorld);
|
m_Renderer.AddRenderer<render::TowerRenderer>(m_Camera, clientWorld);
|
||||||
|
m_Renderer.AddRenderer<render::TimerRenderer>(*gameState);
|
||||||
|
|
||||||
auto& list = m_Renderer.AddRenderer<render::PlayerListRenderer>(m_Client->GetPlayers());
|
auto& list = m_Renderer.AddRenderer<render::PlayerListRenderer>(m_Client->GetPlayers());
|
||||||
|
|
||||||
@@ -73,8 +75,8 @@ DebugWorldState::DebugWorldState(Display& a_Display) : DisplayState(a_Display) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DebugWorldState::Update(float a_Delta) {
|
void DebugWorldState::Update(float a_Delta) {
|
||||||
m_Server->Update(a_Delta);
|
m_Server->Update(a_Delta * m_PlaySpeed);
|
||||||
m_Client->Update(a_Delta);
|
m_Client->Update(a_Delta * m_PlaySpeed);
|
||||||
if (m_ClientState)
|
if (m_ClientState)
|
||||||
m_Renderer.Render(m_ClientState->GetCurrentLerp());
|
m_Renderer.Render(m_ClientState->GetCurrentLerp());
|
||||||
}
|
}
|
||||||
@@ -85,6 +87,7 @@ void DebugWorldState::OnAspectRatioChange(float a_Ratio) {
|
|||||||
|
|
||||||
void DebugWorldState::OnKeyDown(SDL_Keycode a_Key) {
|
void DebugWorldState::OnKeyDown(SDL_Keycode a_Key) {
|
||||||
// temporary tests
|
// temporary tests
|
||||||
|
constexpr int SECONDS = 10;
|
||||||
switch (a_Key) {
|
switch (a_Key) {
|
||||||
case SDLK_A:
|
case SDLK_A:
|
||||||
m_Client->SendPacket(td::protocol::packets::SpawnTroopPacket(td::EntityType::Zombie, 1));
|
m_Client->SendPacket(td::protocol::packets::SpawnTroopPacket(td::EntityType::Zombie, 1));
|
||||||
@@ -94,6 +97,15 @@ void DebugWorldState::OnKeyDown(SDL_Keycode a_Key) {
|
|||||||
m_Client->SendPacket(td::protocol::packets::PlaceTowerPacket(td::TowerType::Archer, td::TowerCoords(77, 13)));
|
m_Client->SendPacket(td::protocol::packets::PlaceTowerPacket(td::TowerType::Archer, td::TowerCoords(77, 13)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SDLK_F:
|
||||||
|
m_Server->Update(SECONDS);
|
||||||
|
m_Client->Update(SECONDS);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_P:
|
||||||
|
m_PlaySpeed = 1 - m_PlaySpeed;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,10 @@
|
|||||||
|
#include <cassert>
|
||||||
|
#include <td/Maths.h>
|
||||||
#include <td/game/World.h>
|
#include <td/game/World.h>
|
||||||
|
#include <td/game/WorldTypes.h>
|
||||||
|
|
||||||
#include <td/simulation/WorldTicker.h>
|
|
||||||
#include <td/protocol/packet/PacketSerialize.h>
|
#include <td/protocol/packet/PacketSerialize.h>
|
||||||
|
#include <td/simulation/WorldTicker.h>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace game {
|
namespace game {
|
||||||
@@ -89,5 +92,14 @@ void World::ResetSnapshots(std::shared_ptr<sim::WorldSnapshot>& a_Current, std::
|
|||||||
m_NextState = a_Next;
|
m_NextState = a_Next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TilePtr World::GetTile(std::int32_t x, std::int32_t y) const {
|
||||||
|
ChunkCoord coords{static_cast<std::int16_t>(x / Chunk::ChunkWidth), static_cast<std::int16_t>(y / Chunk::ChunkHeight)};
|
||||||
|
auto it = m_Chunks.find(coords);
|
||||||
|
assert(it != m_Chunks.end());
|
||||||
|
auto chunk = it->second;
|
||||||
|
Vec2i inchunkCoords{x % Chunk::ChunkWidth, y % Chunk::ChunkHeight};
|
||||||
|
return GetTilePtr(chunk->GetTileIndex(inchunkCoords.y * Chunk::ChunkWidth + inchunkCoords.x));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace game
|
} // namespace game
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "td/Maths.h"
|
||||||
#include <td/render/Camera.h>
|
#include <td/render/Camera.h>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@@ -24,5 +25,9 @@ void Camera::SetCamPos(const Vec3f& a_NewPos) {
|
|||||||
OnViewChange();
|
OnViewChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Vec3f& Camera::GetCamPos() const {
|
||||||
|
return m_CamPos;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace render
|
} // namespace render
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
|||||||
@@ -8,10 +8,17 @@ namespace render {
|
|||||||
void BasicRenderer::Render(const GL::VertexArray& a_Vao) {
|
void BasicRenderer::Render(const GL::VertexArray& a_Vao) {
|
||||||
a_Vao.Bind();
|
a_Vao.Bind();
|
||||||
glDrawArrays(GL_TRIANGLES, 0, a_Vao.GetVertexCount());
|
glDrawArrays(GL_TRIANGLES, 0, a_Vao.GetVertexCount());
|
||||||
// glDrawElements(GL_TRIANGLES, a_Vao.GetVertexCount(), GL_UNSIGNED_INT, nullptr);
|
|
||||||
a_Vao.Unbind();
|
a_Vao.Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BasicRenderer::Render(const Model& a_Model) {
|
||||||
|
for (const auto& vao : a_Model.m_Vaos) {
|
||||||
|
vao->Bind();
|
||||||
|
glDrawElements(GL_TRIANGLES, vao->GetVertexCount(), GL_UNSIGNED_INT, nullptr);
|
||||||
|
vao->Unbind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RenderPipeline::RenderPipeline() {
|
RenderPipeline::RenderPipeline() {
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
|
|||||||
128
src/td/render/loader/FbxLoader.cpp
Normal file
128
src/td/render/loader/FbxLoader.cpp
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
#include <td/render/loader/FbxLoader.h>
|
||||||
|
|
||||||
|
#include <assimp/Importer.hpp> // C++ importer interface
|
||||||
|
#include <assimp/postprocess.h> // Post processing flags
|
||||||
|
#include <assimp/scene.h> // Output data structure
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <sp/common/DataBuffer.h>
|
||||||
|
#include <td/render/loader/GLLoader.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#define VERTEX_SIZE 3
|
||||||
|
#define UV_SIZE 2
|
||||||
|
|
||||||
|
#define VERTEX_POSITION_INDEX 0
|
||||||
|
#define VERTEX_UV_INDEX 1
|
||||||
|
#define VERTEX_NORMAL_INDEX 2
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace ModelLoader {
|
||||||
|
|
||||||
|
static std::unique_ptr<GL::VertexArray> ProcessMesh(aiMesh* mesh, const aiScene* scene, const aiMatrix4x4& transform) {
|
||||||
|
std::vector<float> positions;
|
||||||
|
std::vector<float> textureCoords;
|
||||||
|
std::vector<float> normals;
|
||||||
|
|
||||||
|
std::vector<unsigned int> indicies;
|
||||||
|
|
||||||
|
aiFace* faces = mesh->mFaces;
|
||||||
|
std::size_t faceNumber = mesh->mNumFaces;
|
||||||
|
|
||||||
|
for (std::size_t j = 0; j < faceNumber; j++) {
|
||||||
|
std::size_t offset = indicies.size();
|
||||||
|
std::size_t numIndices = faces[j].mNumIndices;
|
||||||
|
|
||||||
|
indicies.resize(indicies.size() + numIndices);
|
||||||
|
std::memcpy(indicies.data() + offset, faces[j].mIndices, numIndices * sizeof(unsigned int));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t vertNumber = mesh->mNumVertices;
|
||||||
|
aiVector3D* vertecies = mesh->mVertices;
|
||||||
|
|
||||||
|
for (std::size_t j = 0; j < vertNumber; j++) {
|
||||||
|
aiVector3D vertex = transform * vertecies[j];
|
||||||
|
|
||||||
|
positions.push_back(vertex.x);
|
||||||
|
positions.push_back(vertex.y);
|
||||||
|
positions.push_back(vertex.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mesh->HasNormals()) {
|
||||||
|
aiVector3D* vertexNormals = mesh->mNormals;
|
||||||
|
|
||||||
|
for (std::size_t j = 0; j < vertNumber; j++) {
|
||||||
|
aiVector3D normal = transform * vertexNormals[j];
|
||||||
|
|
||||||
|
normals.push_back(normal.x);
|
||||||
|
normals.push_back(normal.y);
|
||||||
|
normals.push_back(normal.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aiVector3D** vertexTexture = mesh->mTextureCoords;
|
||||||
|
|
||||||
|
for (std::size_t j = 0; j < vertNumber; j++) {
|
||||||
|
textureCoords.push_back(vertexTexture[0][j].x);
|
||||||
|
textureCoords.push_back(vertexTexture[0][j].y);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL::VertexBuffer positionVBO(positions, VERTEX_SIZE);
|
||||||
|
positionVBO.AddVertexAttribPointer(VERTEX_POSITION_INDEX, VERTEX_SIZE, 0);
|
||||||
|
|
||||||
|
GL::VertexBuffer textureVBO(textureCoords, UV_SIZE);
|
||||||
|
textureVBO.AddVertexAttribPointer(VERTEX_UV_INDEX, UV_SIZE, 0);
|
||||||
|
|
||||||
|
GL::VertexBuffer normalVBO(normals, VERTEX_SIZE);
|
||||||
|
normalVBO.AddVertexAttribPointer(VERTEX_NORMAL_INDEX, VERTEX_SIZE, 0);
|
||||||
|
|
||||||
|
auto Vao = std::make_unique<GL::VertexArray>(GL::ElementBuffer{indicies});
|
||||||
|
Vao->Bind();
|
||||||
|
Vao->BindVertexBuffer(std::move(positionVBO));
|
||||||
|
Vao->BindVertexBuffer(std::move(textureVBO));
|
||||||
|
Vao->BindVertexBuffer(std::move(normalVBO));
|
||||||
|
Vao->Unbind();
|
||||||
|
|
||||||
|
return Vao;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ProcessNode(
|
||||||
|
aiNode* node, const aiScene* scene, std::vector<std::unique_ptr<GL::VertexArray>>& meshes, const aiMatrix4x4& transform) {
|
||||||
|
// recursive
|
||||||
|
for (unsigned int i = 0; i < node->mNumChildren; i++) {
|
||||||
|
ProcessNode(node->mChildren[i], scene, meshes, transform * node->mTransformation);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < node->mNumMeshes; i++) {
|
||||||
|
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
|
||||||
|
meshes.push_back(ProcessMesh(mesh, scene, transform * node->mTransformation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Model LoadModel(const std::string& fileName) {
|
||||||
|
// DataBuffer fileData = utils::AssetsManager::GetAsset(fileName);
|
||||||
|
sp::DataBuffer fileData;
|
||||||
|
fileData.ReadFile(fileName);
|
||||||
|
|
||||||
|
Assimp::Importer importer;
|
||||||
|
|
||||||
|
const aiScene* scene = importer.ReadFile(fileName, aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_SortByPType |
|
||||||
|
aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes | aiProcess_GlobalScale);
|
||||||
|
|
||||||
|
if (!scene) {
|
||||||
|
std::cerr << "[ModelLoader] Failed to load model !\n";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// utils::LOGD(utils::Format("[ModelLoader]\tModel nodes : %i", scene->mRootNode->mNumMeshes));
|
||||||
|
|
||||||
|
Model model;
|
||||||
|
ProcessNode(scene->mRootNode, scene, model.m_Vaos, {});
|
||||||
|
|
||||||
|
std::cout << "Loaded " << model.m_Vaos.size() << " vaos !\n";
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ModelLoader
|
||||||
|
} // namespace td
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "td/render/Renderer.h"
|
||||||
#include <td/render/renderer/EntityRenderer.h>
|
#include <td/render/renderer/EntityRenderer.h>
|
||||||
|
|
||||||
#include <td/render/loader/WorldLoader.h>
|
#include <td/render/loader/WorldLoader.h>
|
||||||
@@ -6,7 +7,7 @@ namespace td {
|
|||||||
namespace render {
|
namespace render {
|
||||||
|
|
||||||
EntityRenderer::EntityRenderer(Camera& a_Camera, const game::WorldPtr& a_World) : Renderer(a_Camera), m_World(a_World) {
|
EntityRenderer::EntityRenderer(Camera& a_Camera, const game::WorldPtr& a_World) : Renderer(a_Camera), m_World(a_World) {
|
||||||
m_EntityVao = std::make_unique<GL::VertexArray>(WorldLoader::LoadMobModel());
|
m_EntityModel = ModelLoader::LoadModel("assets/zombie.fbx");
|
||||||
m_Shader->Start();
|
m_Shader->Start();
|
||||||
m_Shader->SetColorEffect({1, 0, 1});
|
m_Shader->SetColorEffect({1, 0, 1});
|
||||||
}
|
}
|
||||||
@@ -22,8 +23,8 @@ void EntityRenderer::Render(float a_Lerp) {
|
|||||||
float x = Lerp<game::Mob>(*mob, a_Lerp, [](const game::Mob& a_Mob) { return static_cast<float>(a_Mob.m_Position.x); });
|
float x = Lerp<game::Mob>(*mob, a_Lerp, [](const game::Mob& a_Mob) { return static_cast<float>(a_Mob.m_Position.x); });
|
||||||
float z = Lerp<game::Mob>(*mob, a_Lerp, [](const game::Mob& a_Mob) { return static_cast<float>(a_Mob.m_Position.y); });
|
float z = Lerp<game::Mob>(*mob, a_Lerp, [](const game::Mob& a_Mob) { return static_cast<float>(a_Mob.m_Position.y); });
|
||||||
|
|
||||||
m_Shader->SetModelPos({x, 1, z});
|
m_Shader->SetModelPos({x, .001, z});
|
||||||
Renderer::Render(*m_EntityVao);
|
Renderer::Render(m_EntityModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
18
src/td/render/renderer/TimerRenderer.cpp
Normal file
18
src/td/render/renderer/TimerRenderer.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#include <client/state/GameState.h>
|
||||||
|
#include <td/render/renderer/TimerRenderer.h>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
void TimerRenderer::Render(float a_Lerp) {
|
||||||
|
ImGui::Begin("Timer");
|
||||||
|
ImGui::Text("Time : %02d:%02d", static_cast<int>(m_State.GetElapsedTime()) / 60, static_cast<int>(m_State.GetElapsedTime()) % 60);
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
TimerRenderer::TimerRenderer(const client::GameState& a_State) : m_State(a_State) {}
|
||||||
|
|
||||||
|
} // namespace render
|
||||||
|
} // namespace td
|
||||||
@@ -18,7 +18,7 @@ TowerRenderer::~TowerRenderer() {}
|
|||||||
void TowerRenderer::Render(float a_Lerp) {
|
void TowerRenderer::Render(float a_Lerp) {
|
||||||
m_Shader->Start();
|
m_Shader->Start();
|
||||||
for (const auto& tower : m_World->GetTowers()) {
|
for (const auto& tower : m_World->GetTowers()) {
|
||||||
m_Shader->SetModelPos({tower->GetCenterX(), 1, tower->GetCenterY()});
|
m_Shader->SetModelPos({tower->GetCenterX(), .001, tower->GetCenterY()});
|
||||||
Renderer::Render(*m_EntityVao);
|
Renderer::Render(*m_EntityVao);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <td/Maths.h>
|
||||||
#include <td/render/renderer/WorldRenderer.h>
|
#include <td/render/renderer/WorldRenderer.h>
|
||||||
|
|
||||||
#include <td/render/loader/WorldLoader.h>
|
#include <td/render/loader/WorldLoader.h>
|
||||||
@@ -13,7 +14,17 @@ WorldRenderer::WorldRenderer(Camera& a_Camera, const game::WorldPtr& a_World) :
|
|||||||
|
|
||||||
WorldRenderer::~WorldRenderer() {}
|
WorldRenderer::~WorldRenderer() {}
|
||||||
|
|
||||||
|
void WorldRenderer::UpdateControls() {
|
||||||
|
if (ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
|
||||||
|
constexpr float sensitivity = 1.0f;
|
||||||
|
float delta = ImGui::GetIO().DeltaTime;
|
||||||
|
auto mouseDelta = ImGui::GetIO().MouseDelta;
|
||||||
|
m_Camera.SetCamPos(m_Camera.GetCamPos() + Vec3f{-mouseDelta.x * delta * sensitivity, 0, -mouseDelta.y * delta * sensitivity});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WorldRenderer::Render(float a_Lerp) {
|
void WorldRenderer::Render(float a_Lerp) {
|
||||||
|
UpdateControls();
|
||||||
m_Shader->Start();
|
m_Shader->Start();
|
||||||
Renderer::Render(*m_WorldVao);
|
Renderer::Render(*m_WorldVao);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ float ClientSimulation::Update(float a_Delta) {
|
|||||||
// TODO: handle freezes (m_CurrentTime > 2 * m_StepTime)
|
// TODO: handle freezes (m_CurrentTime > 2 * m_StepTime)
|
||||||
static const float stepTimeSecond = static_cast<float>(m_StepTime) / 1000.0f;
|
static const float stepTimeSecond = static_cast<float>(m_StepTime) / 1000.0f;
|
||||||
m_CurrentTime += a_Delta;
|
m_CurrentTime += a_Delta;
|
||||||
if (m_CurrentTime > stepTimeSecond) {
|
while (m_CurrentTime > stepTimeSecond) {
|
||||||
m_CurrentTime = std::fmod(m_CurrentTime, stepTimeSecond);
|
m_CurrentTime -= stepTimeSecond;
|
||||||
Step();
|
Step();
|
||||||
}
|
}
|
||||||
return (float)m_CurrentTime / stepTimeSecond;
|
return (float)m_CurrentTime / stepTimeSecond;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <td/Types.h>
|
||||||
#include <td/simulation/CommandApply.h>
|
#include <td/simulation/CommandApply.h>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
@@ -24,6 +25,10 @@ void CommandApply::Handle(const protocol::commands::PlayerJoinCommand& a_PlayerJ
|
|||||||
void CommandApply::Handle(const protocol::commands::SpawnTroopCommand& a_SpawnTroop) {
|
void CommandApply::Handle(const protocol::commands::SpawnTroopCommand& a_SpawnTroop) {
|
||||||
auto zombie = std::make_shared<game::Zombie>();
|
auto zombie = std::make_shared<game::Zombie>();
|
||||||
zombie->m_Position = a_SpawnTroop->m_Position;
|
zombie->m_Position = a_SpawnTroop->m_Position;
|
||||||
|
|
||||||
|
// TODO: make it spawn dependant
|
||||||
|
zombie->m_Direction = Direction::PositiveY;
|
||||||
|
|
||||||
m_Snapshot.m_Mobs.push_back(zombie);
|
m_Snapshot.m_Mobs.push_back(zombie);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,61 @@
|
|||||||
|
#include <td/Maths.h>
|
||||||
|
#include <td/Types.h>
|
||||||
|
#include <td/game/WorldTypes.h>
|
||||||
#include <td/simulation/system/EntityMove.h>
|
#include <td/simulation/system/EntityMove.h>
|
||||||
|
|
||||||
|
#include <td/game/World.h>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace sim {
|
namespace sim {
|
||||||
|
|
||||||
|
static Vec2i GetUnitDirection(Direction a_Direction) {
|
||||||
|
switch (a_Direction) {
|
||||||
|
case Direction::PositiveX:
|
||||||
|
return {1, 0};
|
||||||
|
case Direction::NegativeX:
|
||||||
|
return {-1, 0};
|
||||||
|
case Direction::PositiveY:
|
||||||
|
return {0, 1};
|
||||||
|
case Direction::NegativeY:
|
||||||
|
return {0, -1};
|
||||||
|
}
|
||||||
|
return {0, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
class DirectionTileVisitor : public game::TileHandler {
|
||||||
|
private:
|
||||||
|
Direction m_Direction;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DirectionTileVisitor() {}
|
||||||
|
|
||||||
|
virtual void Handle(const game::EmptyTile& a_Tile) override {}
|
||||||
|
|
||||||
|
virtual void Handle(const game::TowerTile& a_Tile) override {}
|
||||||
|
|
||||||
|
virtual void Handle(const game::DecorationTile& a_Tile) override {}
|
||||||
|
|
||||||
|
virtual void Handle(const game::WalkableTile& a_Tile) override {
|
||||||
|
m_Direction = a_Tile->m_Direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Direction GetDirection() {
|
||||||
|
return m_Direction;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void EntityMove::Tick(const game::World& a_World, WorldSnapshot& a_State, FpFloat a_Delta) {
|
void EntityMove::Tick(const game::World& a_World, WorldSnapshot& a_State, FpFloat a_Delta) {
|
||||||
for (auto& mob : a_State.m_Mobs) {
|
for (auto& mob : a_State.m_Mobs) {
|
||||||
mob->m_Position.x += a_Delta;
|
auto tile = a_World.GetTile(static_cast<std::int32_t>(mob->m_Position.x), static_cast<std::int32_t>(mob->m_Position.y));
|
||||||
|
Direction direction = mob->m_Direction;
|
||||||
|
if (tile) {
|
||||||
|
DirectionTileVisitor visitor;
|
||||||
|
tile->Dispatch(visitor);
|
||||||
|
direction = visitor.GetDirection();
|
||||||
|
}
|
||||||
|
auto directVector = GetUnitDirection(direction);
|
||||||
|
mob->m_Position.x += directVector.x * a_Delta;
|
||||||
|
mob->m_Position.y += directVector.y * a_Delta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ add_rules("mode.debug", "mode.release")
|
|||||||
|
|
||||||
add_repositories("persson-repo https://git.ale-pri.com/Persson-dev/xmake-repo.git")
|
add_repositories("persson-repo https://git.ale-pri.com/Persson-dev/xmake-repo.git")
|
||||||
|
|
||||||
add_requires("imgui[sdl3,opengl3] 1.92.1", "splib 2.3.2", "zlib", "glew", "fpm", "enet6")
|
add_requires("imgui 1.92.0", {configs = {sdl3 = true, opengl3 = true}})
|
||||||
|
add_requires("libsdl3 3.2.16", "splib 2.3.2", "zlib", "glew", "fpm", "enet6", "assimp")
|
||||||
|
|
||||||
set_languages("c++20")
|
set_languages("c++20")
|
||||||
|
|
||||||
@@ -16,16 +17,13 @@ else
|
|||||||
set_policy("build.sanitizer.undefined", true)
|
set_policy("build.sanitizer.undefined", true)
|
||||||
end
|
end
|
||||||
|
|
||||||
includes("lib/*.lua")
|
|
||||||
|
|
||||||
target("Tower-Defense2")
|
target("Tower-Defense2")
|
||||||
add_includedirs("include", {public = true})
|
add_includedirs("include", {public = true})
|
||||||
set_kind("binary")
|
set_kind("binary")
|
||||||
add_files("src/**.cpp")
|
add_files("src/**.cpp")
|
||||||
add_packages("libsdl3", "imgui", "glew", "splib", "zlib", "fpm", "enet6", {public = true})
|
add_packages("libsdl3", "imgui", "glew", "splib", "zlib", "fpm", "assimp", "enet6", {public = true})
|
||||||
set_rundir(".")
|
set_rundir(".")
|
||||||
add_defines("TD_GL_LOADER_GLEW")
|
add_defines("TD_GL_LOADER_GLEW")
|
||||||
add_deps("imgui-node-editor")
|
|
||||||
|
|
||||||
|
|
||||||
-- Tests
|
-- Tests
|
||||||
|
|||||||
Reference in New Issue
Block a user