pathfinding
This commit is contained in:
parent
a4b77f420a
commit
a168f51fbd
@ -1,6 +1,7 @@
|
||||
g_require("scripts/thread.lua")
|
||||
g_require("scripts/input.lua")
|
||||
g_require("scripts/player.lua")
|
||||
g_require("scripts/npc.lua")
|
||||
|
||||
print("autoexec")
|
||||
|
||||
@ -24,4 +25,8 @@ onkeypress["KEY_T"] = function ()
|
||||
end
|
||||
|
||||
playercamera = not playercamera
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, 10 do
|
||||
spawnnpc(1 + i, 1, 0, player)
|
||||
end
|
||||
|
||||
@ -64,6 +64,18 @@ function i_setcontrolcallback(callback) end
|
||||
---@return number
|
||||
function ent_spawn(x, y, z, pitch, yaw, roll, sx, sy, sz) end
|
||||
|
||||
---@param ent1 number
|
||||
---@param ent2 number
|
||||
---@return number
|
||||
function ent_distance(ent1, ent2) end
|
||||
|
||||
---@param ent number
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param z number
|
||||
---@return number
|
||||
function ent_distanceto(ent, x, y, z) end
|
||||
|
||||
--- Model
|
||||
|
||||
---@param ent number
|
||||
@ -120,11 +132,10 @@ function cct_getforwardxz(ent) end
|
||||
|
||||
---@param ent number
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param z number
|
||||
---@param speed number
|
||||
---@return nil
|
||||
function cct_turnto(ent, x, y, z, speed) end
|
||||
function cct_turnto(ent, x, z, speed) end
|
||||
|
||||
---@param ent number
|
||||
---@param angle number
|
||||
@ -137,4 +148,18 @@ function cct_turntoangle(ent, angle, speed) end
|
||||
---@param y number
|
||||
---@param z number
|
||||
---@return nil
|
||||
function cct_move(ent, x, y, z) end
|
||||
function cct_move(ent, x, y, z) end
|
||||
|
||||
---@param ent number
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param z number
|
||||
---@return boolean
|
||||
function cct_findpath(ent, x, y, z) end
|
||||
|
||||
---@param ent number
|
||||
---@return boolean found
|
||||
---@return number x
|
||||
---@return number y
|
||||
---@return number z
|
||||
function cct_getnextpathnode(ent) end
|
||||
71
main/scripts/npc.lua
Normal file
71
main/scripts/npc.lua
Normal file
@ -0,0 +1,71 @@
|
||||
g_require("scripts/thread.lua")
|
||||
|
||||
function spawnnpc(x, y, z, follow)
|
||||
local npc = ent_spawn(x, y, z, 0, 0, 0, 1, 1, 1)
|
||||
mdl_set(npc, "models/test_skeletal.mdl.json")
|
||||
mdl_anim(npc, "init", 0, 0)
|
||||
mdl_anim(npc, "stand", 0, 0)
|
||||
cct_add(npc, 0.25, 1.2)
|
||||
|
||||
local tick = 1 / g_gettps()
|
||||
|
||||
local function disttonode(ent, node_x, node_z)
|
||||
local _, ent_y, _ = cct_getpos(ent)
|
||||
return ent_distanceto(ent, node_x, ent_y, node_z)
|
||||
end
|
||||
|
||||
thread(function ()
|
||||
while true do
|
||||
wait(1)
|
||||
|
||||
if ent_distance(npc, follow) > 10 then
|
||||
local follow_x, follow_y, follow_z = cct_getpos(follow)
|
||||
local path_found = cct_findpath(npc, follow_x, follow_y, follow_z)
|
||||
|
||||
print("path found: ", path_found)
|
||||
if path_found then
|
||||
mdl_anim(npc, "walk2", 6, 0.2)
|
||||
|
||||
local walk = true
|
||||
while walk do
|
||||
local next_node, node_x, node_y, node_z = cct_getnextpathnode(npc)
|
||||
print("nextnode: ", next_node, node_x, node_y, node_z)
|
||||
|
||||
if not next_node then
|
||||
break
|
||||
end
|
||||
|
||||
while disttonode(npc, node_x, node_z) > 1 do
|
||||
if ent_distance(npc, follow) < 5 then
|
||||
walk = false
|
||||
break
|
||||
end
|
||||
|
||||
|
||||
cct_turnto(npc, node_x, node_z, 3)
|
||||
local move_x = 0
|
||||
local move_y = -3.0
|
||||
local move_z = 0
|
||||
|
||||
move_x, move_z = cct_getforwardxz(npc)
|
||||
|
||||
cct_move(npc, move_x * tick * 3, move_y * tick * 3, move_z * tick * 3)
|
||||
local new_x, new_y, new_z = cct_getpos(npc)
|
||||
local dist = ent_distanceto(npc, new_x, new_y, new_z)
|
||||
|
||||
-- blocked
|
||||
if dist < tick * 0.2 then
|
||||
walk = false
|
||||
break
|
||||
end
|
||||
|
||||
|
||||
wait(0)
|
||||
end
|
||||
end
|
||||
mdl_stopanim(npc, "walk2", 0.1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
@ -31,7 +31,7 @@ function setupplayer(ent)
|
||||
local move_y = -3.0
|
||||
local move_z = 0
|
||||
|
||||
local movespeed = 3.0
|
||||
local movespeed = 10.0
|
||||
|
||||
if fb ~= 0 or rl ~= 0 then
|
||||
local foward_x, forward_z = g_getcameraforwardxz()
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
using namespace TSR;
|
||||
|
||||
void TSR::Camera::UpdateVectors() {
|
||||
void Camera::UpdateVectors() {
|
||||
auto yaw_rad = glm::radians(yaw);
|
||||
auto pitch_rad = glm::radians(pitch);
|
||||
front_vector = glm::normalize(glm::vec3(cos(yaw_rad) * glm::cos(pitch_rad), glm::sin(pitch_rad), glm::sin(yaw_rad) * glm::cos(pitch_rad)));
|
||||
@ -12,7 +12,7 @@ void TSR::Camera::UpdateVectors() {
|
||||
up_vector = glm::normalize(glm::cross(right_vector, front_vector));
|
||||
}
|
||||
|
||||
TSR::Camera::Camera(glm::vec3 i_position, float i_movement_speed, float i_mouse_sensitivity, float i_third_person_distance, float i_yaw, float i_pitch) :
|
||||
Camera::Camera(glm::vec3 i_position, float i_movement_speed, float i_mouse_sensitivity, float i_third_person_distance, float i_yaw, float i_pitch) :
|
||||
position(i_position),
|
||||
movement_speed(i_movement_speed),
|
||||
mouse_sensitivity(i_mouse_sensitivity),
|
||||
@ -24,7 +24,7 @@ TSR::Camera::Camera(glm::vec3 i_position, float i_movement_speed, float i_mouse_
|
||||
UpdateVectors();
|
||||
}
|
||||
|
||||
glm::mat4 TSR::Camera::GetViewMatrix(bool firstperson) {
|
||||
glm::mat4 Camera::GetViewMatrix(bool firstperson) {
|
||||
float space = 0.3f;
|
||||
auto dist = firstperson ? 0.0f : third_person_distance;
|
||||
|
||||
@ -48,7 +48,7 @@ glm::mat4 TSR::Camera::GetViewMatrix(bool firstperson) {
|
||||
return glm::lookAt(position - front_vector * dist, position + front_vector, up_vector);
|
||||
}
|
||||
|
||||
void TSR::Camera::ProcessMovement(Movement direction, float time) {
|
||||
void Camera::ProcessMovement(Movement direction, float time) {
|
||||
float diff = movement_speed * time;
|
||||
switch (direction) {
|
||||
case Movement::FORWARD:
|
||||
@ -72,7 +72,7 @@ void TSR::Camera::ProcessMovement(Movement direction, float time) {
|
||||
}
|
||||
}
|
||||
|
||||
void TSR::Camera::ProcessMouse(float x_offset, float y_offset) {
|
||||
void Camera::ProcessMouse(float x_offset, float y_offset) {
|
||||
yaw += x_offset * mouse_sensitivity;
|
||||
//pitch = std::min(89.0f, std::max(-89.0f, pitch + y_offset * mouse_sensitivity));
|
||||
pitch = std::min(89.9f, std::max(-89.9f, pitch + y_offset * mouse_sensitivity));
|
||||
|
||||
@ -30,4 +30,20 @@ void EntitySystem::RegisterLuaFunctions() {
|
||||
LuaAPI::RegisterFunction("ent_despawn", [](entt::entity ent) {
|
||||
EntitySystem::Despawn(ent);
|
||||
});
|
||||
|
||||
LuaAPI::RegisterFunction("ent_distance", [](entt::entity ent, entt::entity other) {
|
||||
auto& reg = Game::Registry();
|
||||
auto& trans1 = reg.get<TransformComponent>(ent);
|
||||
auto& trans2 = reg.get<TransformComponent>(other);
|
||||
|
||||
return glm::distance(trans1.trans.pos, trans2.trans.pos);
|
||||
});
|
||||
|
||||
LuaAPI::RegisterFunction("ent_distanceto", [](entt::entity ent, float x, float y, float z) {
|
||||
auto& reg = Game::Registry();
|
||||
auto& trans1 = reg.get<TransformComponent>(ent);
|
||||
glm::vec3 pos(x, y, z);
|
||||
|
||||
return glm::distance(trans1.trans.pos, pos);
|
||||
});
|
||||
}
|
||||
|
||||
@ -58,9 +58,10 @@ static bool CCTTurnToAngle(CCTComponent& comp, float target, float speed) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool CCTTurnTo(CCTComponent& comp, const glm::vec3& pos, float step) {
|
||||
auto diff = pos - CCTGetPos(comp);
|
||||
auto target = std::atan2(pos.x, pos.z);
|
||||
static bool CCTTurnTo(CCTComponent& comp, const glm::vec2& pos, float step) {
|
||||
auto self_pos = CCTGetPos(comp);
|
||||
auto diff = pos - glm::vec2(self_pos.x, self_pos.z);
|
||||
auto target = std::atan2(diff.x, diff.y);
|
||||
|
||||
return CCTTurnToAngle(comp, target, step);
|
||||
}
|
||||
@ -135,7 +136,7 @@ glm::vec3 CCTSystem::GetForward(entt::entity ent) {
|
||||
return glm::vec3(std::sin(comp.angle), 0.0f, std::cos(comp.angle));
|
||||
}
|
||||
|
||||
bool CCTSystem::TurnTo(entt::entity ent, const glm::vec3& pos, float speed) {
|
||||
bool CCTSystem::TurnTo(entt::entity ent, const glm::vec2& pos, float speed) {
|
||||
auto& reg = Game::Registry();
|
||||
auto& comp = reg.get<CCTComponent>(ent);
|
||||
|
||||
@ -149,6 +150,30 @@ bool CCTSystem::TurnToAngle(entt::entity ent, float target, float speed) {
|
||||
return CCTTurnToAngle(comp, target, speed);
|
||||
}
|
||||
|
||||
bool CCTSystem::FindPath(entt::entity ent, const glm::vec3& end) {
|
||||
auto& reg = Game::Registry();
|
||||
auto& comp = reg.get<CCTComponent>(ent);
|
||||
|
||||
auto start = CCTGetPos(comp);
|
||||
start.y += 0.5f;
|
||||
|
||||
return Game::Map().GetNodeGraph().FindPath(start, end, comp.path);
|
||||
}
|
||||
|
||||
bool CCTSystem::GetNextPathNode(entt::entity ent, glm::vec3& node) {
|
||||
auto& reg = Game::Registry();
|
||||
auto& comp = reg.get<CCTComponent>(ent);
|
||||
|
||||
if (comp.path.empty())
|
||||
return false;
|
||||
|
||||
node = comp.path.back();
|
||||
comp.path.pop_back();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CCTSystem::Update() {
|
||||
auto& reg = Game::Registry();
|
||||
|
||||
@ -161,7 +186,26 @@ void CCTSystem::Update() {
|
||||
|
||||
}
|
||||
|
||||
void TSR::CCTSystem::RegisterLuaFunctions() {
|
||||
void CCTSystem::DebugDraw(Renderer& renderer) {
|
||||
auto& reg = Game::Registry();
|
||||
|
||||
auto v = reg.view<CCTComponent, TransformComponent>();
|
||||
for (auto [ent, cct, trans] : v.each()) {
|
||||
if (cct.path.empty())
|
||||
return;
|
||||
|
||||
glm::vec3 start_pos = CCTGetPos(cct);
|
||||
|
||||
for (int i = cct.path.size() - 1; i > 0; --i) {
|
||||
auto& node = cct.path[i];
|
||||
renderer.AddDebugLine(start_pos, node, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f));
|
||||
start_pos = node;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CCTSystem::RegisterLuaFunctions() {
|
||||
LuaAPI::RegisterFunction("cct_add", [](entt::entity ent, float radius, float height) {
|
||||
CCTSystem::AddCCT(ent, radius, height);
|
||||
});
|
||||
@ -190,12 +234,24 @@ void TSR::CCTSystem::RegisterLuaFunctions() {
|
||||
return std::make_tuple(forward.x, forward.z);
|
||||
});
|
||||
|
||||
LuaAPI::RegisterFunction("cct_turnto", [](entt::entity ent, float x, float y, float z, float speed) {
|
||||
auto pos = glm::vec3(x, y, z);
|
||||
return CCTSystem::TurnTo(ent, pos, speed);
|
||||
LuaAPI::RegisterFunction("cct_turnto", [](entt::entity ent, float x, float z, float speed) {
|
||||
return CCTSystem::TurnTo(ent, glm::vec2(x, z), speed);
|
||||
});
|
||||
|
||||
LuaAPI::RegisterFunction("cct_turntoangle", [](entt::entity ent, float angle, float speed) {
|
||||
return CCTSystem::TurnToAngle(ent, angle, speed);
|
||||
});
|
||||
|
||||
LuaAPI::RegisterFunction("cct_findpath", [](entt::entity ent, float x, float y, float z) {
|
||||
auto pos = glm::vec3(x, y, z);
|
||||
return CCTSystem::FindPath(ent, pos);
|
||||
});
|
||||
|
||||
LuaAPI::RegisterFunction("cct_getnextpathnode", [](entt::entity ent) {
|
||||
glm::vec3 node;
|
||||
if (CCTSystem::GetNextPathNode(ent, node))
|
||||
return std::make_tuple(true, node.x, node.y, node.z);
|
||||
else
|
||||
return std::make_tuple(false, 0.0f, 0.0f, 0.0f);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "entity.hpp"
|
||||
#include "paths.hpp"
|
||||
|
||||
namespace TSR {
|
||||
|
||||
@ -14,6 +15,8 @@ namespace TSR {
|
||||
PxController* cct;
|
||||
float angle;
|
||||
|
||||
std::vector<glm::vec3> path;
|
||||
|
||||
CCTComponent(float radius, float height, const glm::vec3& pos);
|
||||
CCTComponent(const CCTComponent& other) = delete;
|
||||
~CCTComponent();
|
||||
@ -24,17 +27,22 @@ namespace TSR {
|
||||
public:
|
||||
static void AddCCT(entt::entity ent, float radius, float height);
|
||||
static void RemoveCCT(entt::entity ent);
|
||||
|
||||
static int Move(entt::entity ent, const glm::vec3& disp, float dt);
|
||||
static void SetPos(entt::entity ent, const glm::vec3& pos);
|
||||
static glm::vec3 GetPos(entt::entity ent);
|
||||
|
||||
static glm::vec3 GetForward(entt::entity ent);
|
||||
|
||||
static bool TurnTo(entt::entity ent, const glm::vec3& pos, float step);
|
||||
static bool TurnTo(entt::entity ent, const glm::vec2& pos, float step);
|
||||
static bool TurnToAngle(entt::entity ent, float target, float step);
|
||||
|
||||
static bool FindPath(entt::entity ent, const glm::vec3& end);
|
||||
static bool GetNextPathNode(entt::entity ent, glm::vec3& node);
|
||||
|
||||
static void Update();
|
||||
|
||||
static void DebugDraw(Renderer& renderer);
|
||||
|
||||
static void RegisterLuaFunctions();
|
||||
|
||||
};
|
||||
|
||||
@ -25,6 +25,7 @@ float Game::s_frame_t = 0.0f;
|
||||
int Game::s_tps = 50;
|
||||
|
||||
bool Game::s_debug_draw = false;
|
||||
int Game::s_debug_mode = DEBUG_ALL;
|
||||
|
||||
static Camera cam;
|
||||
|
||||
@ -164,6 +165,19 @@ void Game::Run() {
|
||||
s_physics_scene->EnableDebug(s_debug_draw);
|
||||
break;
|
||||
}
|
||||
|
||||
if (key != GLFW_KEY_F1 && Window::KeyDown(GLFW_KEY_F1)) {
|
||||
switch (key) {
|
||||
case GLFW_KEY_P:
|
||||
s_debug_mode ^= DEBUG_PHYSICS;
|
||||
break;
|
||||
case GLFW_KEY_C:
|
||||
s_debug_mode ^= DEBUG_CCT;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (action == GLFW_PRESS || action == GLFW_RELEASE)
|
||||
@ -250,9 +264,15 @@ void Game::ClFrame(Renderer& renderer, float frame_t) {
|
||||
ModelSystem::Render(renderer);
|
||||
s_map->Draw(renderer);
|
||||
|
||||
if (s_debug_draw)
|
||||
if (DebugEnabled(DEBUG_PHYSICS))
|
||||
s_physics_scene->DrawDebug(renderer);
|
||||
|
||||
if (DebugEnabled(DEBUG_CCT))
|
||||
CCTSystem::DebugDraw(renderer);
|
||||
|
||||
if (DebugEnabled(DEBUG_NODES))
|
||||
s_map->GetNodeGraph().DebugDraw(renderer);
|
||||
|
||||
if (s_skybox_model)
|
||||
s_skybox_model->Draw(renderer, nullptr);
|
||||
|
||||
|
||||
@ -19,6 +19,14 @@ namespace TSR {
|
||||
LuaReference callback;
|
||||
};
|
||||
|
||||
enum DebugMode : int {
|
||||
DEBUG_NONE,
|
||||
DEBUG_PHYSICS = 1 << 0,
|
||||
DEBUG_CCT = 1 << 1,
|
||||
DEBUG_NODES = 1 << 2,
|
||||
DEBUG_ALL = DEBUG_PHYSICS | DEBUG_CCT | DEBUG_NODES
|
||||
};
|
||||
|
||||
class Game {
|
||||
|
||||
static entt::registry s_registry;
|
||||
@ -32,22 +40,24 @@ namespace TSR {
|
||||
static int s_tps;
|
||||
|
||||
static bool s_debug_draw;
|
||||
static int s_debug_mode;
|
||||
|
||||
static void StartGame(const std::string& map_name);
|
||||
static void EndGame();
|
||||
|
||||
public:
|
||||
|
||||
|
||||
static void Run();
|
||||
static void SvFrame();
|
||||
static void ClFrame(Renderer& renderer, float frame_t);
|
||||
|
||||
static entt::registry& Registry() { return s_registry; }
|
||||
static PhysicsScene& Physics() { return *s_physics_scene; }
|
||||
static const WorldMap& Map() { return *s_map; }
|
||||
static uint64_t FrameNum() { return s_sv_frame; }
|
||||
static float FrameT() { return s_frame_t; }
|
||||
static int TPS() { return s_tps; }
|
||||
static bool DebugEnabled(DebugMode mode) { return s_debug_draw && (s_debug_mode & mode); }
|
||||
|
||||
static void RegisterLuaFunctions();
|
||||
|
||||
|
||||
138
src/tsr/paths.cpp
Normal file
138
src/tsr/paths.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
#include "paths.hpp"
|
||||
#include <queue>
|
||||
|
||||
using namespace TSR;
|
||||
|
||||
int NodeGraph::FindClosestNode(const glm::vec3& position) const {
|
||||
float min_dist = std::numeric_limits<float>::max();
|
||||
int min_node = -1;
|
||||
|
||||
for (int i = 0; i < m_nodes.size(); ++i) {
|
||||
auto& node = m_nodes[i];
|
||||
auto dist = glm::distance(node.position, position);
|
||||
|
||||
if (dist < min_dist) {
|
||||
min_dist = dist;
|
||||
min_node = i;
|
||||
}
|
||||
}
|
||||
|
||||
return min_node;
|
||||
}
|
||||
|
||||
// This is a helper function to calculate the heuristic cost between two vectors
|
||||
static float Heuristic(const glm::vec3& a, const glm::vec3& b) {
|
||||
//return std::sqrt(std::pow(a.x - b.x, 2) + std::pow(a.y - b.y, 2) + std::pow(a.z - b.z, 2));
|
||||
return glm::distance(a, b);
|
||||
}
|
||||
|
||||
//using Heuristic = glm::distance;
|
||||
|
||||
|
||||
NodeGraph::NodeGraph() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
void NodeGraph::AddNode(const glm::vec3& position) {
|
||||
m_nodes.push_back(PathNode(position));
|
||||
}
|
||||
|
||||
void NodeGraph::Build(std::function<bool(const glm::vec3&, const glm::vec3&)> test_reach_cb) {
|
||||
for (int i = 0; i < m_nodes.size(); ++i) {
|
||||
for (int j = 0; j < m_nodes.size(); ++j) {
|
||||
if (i == j)
|
||||
continue;
|
||||
|
||||
auto& node = m_nodes[i];
|
||||
auto& other_node = m_nodes[j];
|
||||
|
||||
if (glm::distance(node.position, other_node.position) > 10.0f)
|
||||
continue;
|
||||
|
||||
if (test_reach_cb(node.position, other_node.position))
|
||||
node.reachable_nodes[node.num_reachable_nodes++] = j;
|
||||
|
||||
if (node.num_reachable_nodes == TSR_MAX_REACHABLE_PATHNODES)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool NodeGraph::FindPath(const glm::vec3& start, const glm::vec3& end, std::vector<glm::vec3>& path) const {
|
||||
auto start_id = FindClosestNode(start);
|
||||
auto end_id = FindClosestNode(end);
|
||||
|
||||
// Create a map to store the costs of visiting each node
|
||||
std::unordered_map<int, float> cost_so_far;
|
||||
|
||||
// Create a map to store the best known path to each node
|
||||
std::unordered_map<int, int> came_from;
|
||||
|
||||
// Create a priority queue to store the nodes to be explored,
|
||||
// with the cost as the priority
|
||||
std::priority_queue<std::pair<float, int>, std::vector<std::pair<float, int>>, std::greater<std::pair<float, int>>> frontier;
|
||||
|
||||
// Add the start node to the queue with a cost of 0
|
||||
frontier.emplace(0, start_id);
|
||||
cost_so_far[start_id] = 0;
|
||||
|
||||
// Loop until the queue is empty
|
||||
while (!frontier.empty()) {
|
||||
// Get the node with the lowest cost
|
||||
int current_id = frontier.top().second;
|
||||
frontier.pop();
|
||||
|
||||
// If we have reached the end, construct the path and return it
|
||||
if (current_id == end_id) {
|
||||
//std::vector<int> path;
|
||||
path.clear();
|
||||
while (current_id != start_id) {
|
||||
path.emplace_back(m_nodes[current_id].position);
|
||||
current_id = came_from[current_id];
|
||||
}
|
||||
//path.emplace_back(m_nodes[start_id].position);
|
||||
//std::reverse(path.begin(), path.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Explore all of the reachable nodes from the current node
|
||||
for (int i = 0; i < m_nodes[current_id].num_reachable_nodes; ++i) {
|
||||
int next_id = m_nodes[current_id].reachable_nodes[i];
|
||||
|
||||
// Calculate the cost to reach this node
|
||||
float new_cost = cost_so_far[current_id] + 1; // Add 1 as a simple distance heuristic
|
||||
|
||||
// If this node has not been visited or if the new cost is lower than the previous cost,
|
||||
// update the cost and add it to the queue
|
||||
if (!cost_so_far.contains(next_id) || new_cost < cost_so_far[next_id]) {
|
||||
cost_so_far[next_id] = new_cost;
|
||||
float priority = new_cost + Heuristic(m_nodes[end_id].position, m_nodes[next_id].position); // Add the heuristic cost to the priority queue
|
||||
frontier.emplace(priority, next_id);
|
||||
came_from[next_id] = current_id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If we couldn't find a path, return an empty vector
|
||||
return {};
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void NodeGraph::DebugDraw(Renderer& renderer) const {
|
||||
for (int i = 0; i < m_nodes.size(); ++i) {
|
||||
auto& node = m_nodes[i];
|
||||
renderer.AddDebugPoint(node.position, glm::vec3(1.0f, 0.0f, 1.0f));
|
||||
|
||||
for (int j = 0; j < node.num_reachable_nodes; ++j) {
|
||||
auto& other_node = m_nodes[node.reachable_nodes[j]];
|
||||
renderer.AddDebugLine(node.position, other_node.position, glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/tsr/paths.hpp
Normal file
33
src/tsr/paths.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include "tsr.hpp"
|
||||
#include "renderer.hpp"
|
||||
|
||||
namespace TSR {
|
||||
|
||||
struct PathNode {
|
||||
glm::vec3 position;
|
||||
int num_reachable_nodes;
|
||||
int reachable_nodes[TSR_MAX_REACHABLE_PATHNODES];
|
||||
|
||||
PathNode(const glm::vec3& position) : position(position), num_reachable_nodes(0) {}
|
||||
};
|
||||
|
||||
class NodeGraph {
|
||||
std::vector<PathNode> m_nodes;
|
||||
|
||||
int FindClosestNode(const glm::vec3& position) const;
|
||||
|
||||
public:
|
||||
NodeGraph();
|
||||
|
||||
void AddNode(const glm::vec3& position);
|
||||
void Build(std::function<bool(const glm::vec3&, const glm::vec3&)> test_reach_cb);
|
||||
|
||||
//void FindPath(const glm::vec3& start, const glm::vec3& end, std::vector<glm::vec3>& path) const;
|
||||
|
||||
bool FindPath(const glm::vec3& start, const glm::vec3& end, std::vector<glm::vec3>& path) const;
|
||||
const glm::vec3& GetNodePosition(int id) const { return m_nodes[id].position; }
|
||||
|
||||
void DebugDraw(Renderer& renderer) const;
|
||||
};
|
||||
}
|
||||
@ -586,6 +586,15 @@ void Renderer::Render(int width, int height) {
|
||||
m_debug_vao.Draw(m_debug_lines, true);
|
||||
}
|
||||
|
||||
if (!m_debug_points.empty()) {
|
||||
//glStencilFunc(GL_ALWAYS, 0, 0xFF);
|
||||
m_shader_debug.Use();
|
||||
glUniformMatrix4fv(m_shader_debug.U(SU_VP), 1, GL_FALSE, glm::value_ptr(mat_vp));
|
||||
|
||||
glPointSize(10);
|
||||
m_debug_vao.Draw(m_debug_points, false);
|
||||
}
|
||||
|
||||
// SKYBOX
|
||||
if (!m_draw_lists[RT_SKYBOX].empty()) {
|
||||
m_shader_skybox.Use();
|
||||
@ -647,4 +656,5 @@ void Renderer::Render(int width, int height) {
|
||||
m_draw_lists[i].clear();
|
||||
|
||||
m_debug_lines.clear();
|
||||
m_debug_points.clear();
|
||||
}
|
||||
|
||||
@ -288,6 +288,7 @@ namespace TSR {
|
||||
|
||||
std::vector<DrawRef> m_draw_lists[RT_COUNT];
|
||||
std::vector<DebugVertex> m_debug_lines;
|
||||
std::vector<DebugVertex> m_debug_points;
|
||||
|
||||
Shader m_shader_basic;
|
||||
Shader m_shader_basic_instanced;
|
||||
@ -328,6 +329,10 @@ namespace TSR {
|
||||
m_debug_lines.push_back({ p2, color2 });
|
||||
}
|
||||
|
||||
void AddDebugPoint(const glm::vec3& p, const glm::vec3& color = glm::vec3(1.0f)) {
|
||||
m_debug_points.push_back({ p, color });
|
||||
}
|
||||
|
||||
void SetViewMatrix(const glm::mat4& view_matrix) {
|
||||
m_view_matrix = view_matrix;
|
||||
}
|
||||
|
||||
@ -24,6 +24,9 @@
|
||||
|
||||
#define TSR_NUM_COLORS 4
|
||||
|
||||
#define TSR_MAX_REACHABLE_PATHNODES 32
|
||||
|
||||
|
||||
#define U8(_S) (const char*)u8##_S
|
||||
|
||||
namespace TSR {
|
||||
|
||||
@ -48,9 +48,9 @@ int WorldMap::LoadNext() {
|
||||
|
||||
PhysicalObject phyobj;
|
||||
ctx.model_matrix = glm::rotate(glm::translate(glm::mat4(1.0f), pos), glm::radians(rot), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
phyobj.m_transform = PxTransform(PxMat44(glm::value_ptr(ctx.model_matrix)));
|
||||
phyobj.transform = PxTransform(PxMat44(glm::value_ptr(ctx.model_matrix)));
|
||||
ctx.model_matrix = glm::scale(ctx.model_matrix, glm::vec3(scale));
|
||||
phyobj.m_scale = scale;
|
||||
phyobj.scale = scale;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
auto& cns = color_strs[i];
|
||||
@ -58,8 +58,8 @@ int WorldMap::LoadNext() {
|
||||
ctx.colors[i] = JsonGetVec<4>(j_object.at(cns));
|
||||
}
|
||||
|
||||
model_instances.m_contexts.push_back(ctx);
|
||||
model_instances.m_physical_objects.push_back(phyobj);
|
||||
model_instances.contexts.push_back(ctx);
|
||||
model_instances.physical_object.push_back(phyobj);
|
||||
}
|
||||
|
||||
m_loading_iter = m_loading_obj_data.cbegin();
|
||||
@ -73,7 +73,7 @@ int WorldMap::LoadNext() {
|
||||
case LoadingPhase::MODELS:
|
||||
{
|
||||
if (m_loading_iter == m_loading_obj_data.cend()) {
|
||||
m_loading_phase = LoadingPhase::FINISHED;
|
||||
m_loading_phase = LoadingPhase::PATHNODES;
|
||||
m_loading_obj_data.clear();
|
||||
return 100;
|
||||
}
|
||||
@ -83,21 +83,21 @@ int WorldMap::LoadNext() {
|
||||
|
||||
auto s = AssetMap::Get<Model>(models.first);
|
||||
|
||||
if (models.second.m_contexts.size() > 4) {
|
||||
if (models.second.contexts.size() > 4) {
|
||||
MapObject obj;
|
||||
obj.m_model = s;
|
||||
obj.m_ctx.ssbo = std::make_unique<InstancedSSBO>(models.second.m_contexts);
|
||||
obj.model = s;
|
||||
obj.ctx.ssbo = std::make_unique<InstancedSSBO>(models.second.contexts);
|
||||
|
||||
m_objects_instanced.push_back(std::move(obj));
|
||||
|
||||
}
|
||||
else {
|
||||
for (const auto& instance : models.second.m_contexts) {
|
||||
for (const auto& instance : models.second.contexts) {
|
||||
MapObject obj;
|
||||
obj.m_model = s;
|
||||
obj.m_ctx.model_matrix = instance.model_matrix;
|
||||
obj.model = s;
|
||||
obj.ctx.model_matrix = instance.model_matrix;
|
||||
for (int i = 0; i < 4; i++)
|
||||
obj.m_ctx.colors[i] = instance.colors[i];
|
||||
obj.ctx.colors[i] = instance.colors[i];
|
||||
|
||||
m_objects.push_back(std::move(obj));
|
||||
}
|
||||
@ -108,9 +108,9 @@ int WorldMap::LoadNext() {
|
||||
auto material = AssetMap::Get<PhysicsMaterial>("physics/default.material.json");
|
||||
auto& shape = s->TriMesh();
|
||||
|
||||
for (const auto& phyobj : models.second.m_physical_objects) {
|
||||
PxRigidStatic* actor = Physics::GetPhysics()->createRigidStatic(phyobj.m_transform);
|
||||
PxShape* px_shape = PxRigidActorExt::createExclusiveShape(*actor, PxTriangleMeshGeometry(shape.Get(), PxMeshScale(phyobj.m_scale)), *material->Get());
|
||||
for (const auto& phyobj : models.second.physical_object) {
|
||||
PxRigidStatic* actor = Physics::GetPhysics()->createRigidStatic(phyobj.transform);
|
||||
PxShape* px_shape = PxRigidActorExt::createExclusiveShape(*actor, PxTriangleMeshGeometry(shape.Get(), PxMeshScale(phyobj.scale)), *material->Get());
|
||||
|
||||
m_physics_scene->GetScene()->addActor(*actor);
|
||||
|
||||
@ -121,15 +121,15 @@ int WorldMap::LoadNext() {
|
||||
else if (s->Shape() == SHAPE_BOX) {
|
||||
auto material = AssetMap::Get<PhysicsMaterial>("physics/default.material.json");
|
||||
|
||||
for (const auto& phyobj : models.second.m_physical_objects) {
|
||||
auto transform = phyobj.m_transform;
|
||||
for (const auto& phyobj : models.second.physical_object) {
|
||||
auto transform = phyobj.transform;
|
||||
auto size = s->ShapeSize();
|
||||
auto offset = s->ShapeOffset();
|
||||
transform.p = transform.p + PxVec3(offset.x * phyobj.m_scale, offset.y * phyobj.m_scale, offset.z * phyobj.m_scale);
|
||||
transform.p = transform.p + PxVec3(offset.x * phyobj.scale, offset.y * phyobj.scale, offset.z * phyobj.scale);
|
||||
|
||||
PxRigidStatic* actor = Physics::GetPhysics()->createRigidStatic(transform);
|
||||
|
||||
PxShape* px_shape = PxRigidActorExt::createExclusiveShape(*actor, PxBoxGeometry(size.x * phyobj.m_scale, size.y * phyobj.m_scale, size.z * phyobj.m_scale), *material->Get());
|
||||
PxShape* px_shape = PxRigidActorExt::createExclusiveShape(*actor, PxBoxGeometry(size.x * phyobj.scale, size.y * phyobj.scale, size.z * phyobj.scale), *material->Get());
|
||||
m_physics_scene->GetScene()->addActor(*actor);
|
||||
|
||||
}
|
||||
@ -142,6 +142,38 @@ int WorldMap::LoadNext() {
|
||||
break;
|
||||
}
|
||||
|
||||
case LoadingPhase::PATHNODES:
|
||||
{
|
||||
auto j_map = nlohmann::json::parse(Filesystem::Read(m_map_path));
|
||||
|
||||
if (j_map.contains("pathnodes")) {
|
||||
auto j_pathnodes = j_map.at("pathnodes");
|
||||
|
||||
for (const auto& j_pathnode : j_pathnodes) {
|
||||
auto pos = JsonGetVec<3>(j_pathnode);
|
||||
m_node_graph.AddNode(pos);
|
||||
}
|
||||
|
||||
m_node_graph.Build([this](const glm::vec3& a, const glm::vec3& b) {
|
||||
auto dir = glm::normalize(b - a);
|
||||
auto dist = glm::distance(a, b);
|
||||
|
||||
PxRaycastBuffer hit;
|
||||
bool status = m_physics_scene->GetScene()->raycast(PxVec3(a.x, a.y, a.z), PxVec3(dir.x, dir.y, dir.z), dist, hit);
|
||||
|
||||
if (status)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
m_loading_phase = LoadingPhase::FINISHED;
|
||||
return 100;
|
||||
break;
|
||||
}
|
||||
|
||||
case LoadingPhase::FINISHED:
|
||||
return 100;
|
||||
break;
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "window.hpp"
|
||||
#include "tsr.hpp"
|
||||
#include "physics.hpp"
|
||||
#include "paths.hpp"
|
||||
|
||||
namespace TSR {
|
||||
|
||||
@ -18,17 +19,18 @@ namespace TSR {
|
||||
FIRST,
|
||||
PARSE,
|
||||
MODELS,
|
||||
PATHNODES,
|
||||
FINISHED,
|
||||
} m_loading_phase;
|
||||
|
||||
struct PhysicalObject {
|
||||
PxTransform m_transform;
|
||||
float m_scale;
|
||||
PxTransform transform;
|
||||
float scale;
|
||||
};
|
||||
|
||||
struct ModelInstances {
|
||||
std::vector<BasicDrawCtx> m_contexts;
|
||||
std::vector<PhysicalObject> m_physical_objects;
|
||||
std::vector<BasicDrawCtx> contexts;
|
||||
std::vector<PhysicalObject> physical_object;
|
||||
};
|
||||
|
||||
using LoadingObjData = std::map<std::string, ModelInstances>;
|
||||
@ -39,13 +41,15 @@ namespace TSR {
|
||||
|
||||
// final
|
||||
struct MapObject {
|
||||
DrawCtx m_ctx;
|
||||
AssetPtr<Model> m_model;
|
||||
DrawCtx ctx;
|
||||
AssetPtr<Model> model;
|
||||
};
|
||||
|
||||
std::vector<MapObject> m_objects;
|
||||
std::vector<MapObject> m_objects_instanced;
|
||||
|
||||
NodeGraph m_node_graph;
|
||||
|
||||
public:
|
||||
WorldMap(const std::string& map_path, PhysicsScene* physics_scene);
|
||||
|
||||
@ -56,11 +60,14 @@ namespace TSR {
|
||||
|
||||
void Draw(Renderer& r) const {
|
||||
for (const auto& obj : m_objects)
|
||||
obj.m_model->Draw(r, &obj.m_ctx);
|
||||
obj.model->Draw(r, &obj.ctx);
|
||||
|
||||
for (const auto& obj : m_objects_instanced)
|
||||
obj.m_model->DrawInstanced(r, &obj.m_ctx);
|
||||
obj.model->DrawInstanced(r, &obj.ctx);
|
||||
}
|
||||
|
||||
const NodeGraph& GetNodeGraph() const { return m_node_graph; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -129,6 +129,7 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\tsr\paths.cpp" />
|
||||
<ClCompile Include="src\tsr\entity.cpp" />
|
||||
<ClCompile Include="src\tsr\input.cpp" />
|
||||
<ClCompile Include="src\tsr\luaapi.cpp" />
|
||||
@ -147,6 +148,7 @@
|
||||
<ClCompile Include="src\tsr\worldmap.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\tsr\paths.hpp" />
|
||||
<ClInclude Include="src\tsr\input.hpp" />
|
||||
<ClInclude Include="src\tsr\luaapi.hpp" />
|
||||
<ClInclude Include="src\tsr\entity_cct.hpp" />
|
||||
|
||||
@ -63,6 +63,9 @@
|
||||
<ClCompile Include="src\tsr\entity.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tsr\paths.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\tsr\window.hpp">
|
||||
@ -116,5 +119,8 @@
|
||||
<ClInclude Include="src\tsr\input.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\tsr\paths.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Loading…
x
Reference in New Issue
Block a user