Working on navigation system
This commit is contained in:
1 parent
d4bc73f732
commit
a479fa4ac1
8 files changed
+481
-30
No files matched your search
+152
-20
@@ -7,12 +7,14 @@
|
||||
#include <random>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <cfloat>
|
||||
#include "GameConstants.h"
|
||||
#include "Character.h"
|
||||
#include "external/nlohmann/json.hpp"
|
||||
#include <SDL.h>
|
||||
|
||||
|
||||
namespace ZL
|
||||
@@ -163,6 +165,8 @@ namespace ZL
|
||||
false
|
||||
});*/
|
||||
|
||||
navigationEditorConfigPath = params.navigationJsonPath;
|
||||
|
||||
scriptEngine.init(this, &inventory, params.scriptPath);
|
||||
|
||||
|
||||
@@ -233,9 +237,9 @@ namespace ZL
|
||||
// NPC + player are handled as dynamic obstacles, so they are intentionally NOT in JSON.
|
||||
navigation.build({}, navigationJsonPath, CONST_ZIP_FILE);
|
||||
|
||||
#ifdef SHOW_PATH
|
||||
buildDebugNavMeshes();
|
||||
#endif
|
||||
if (navigationEditorMode) {
|
||||
navigationEditorBuildNavMeshes();
|
||||
}
|
||||
|
||||
static constexpr float kDynamicObstacleInfluenceDist = 6.0f;
|
||||
|
||||
@@ -278,34 +282,145 @@ namespace ZL
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SHOW_PATH
|
||||
void Location::buildDebugNavMeshes()
|
||||
void Location::navigationEditorBuildNavMeshes()
|
||||
{
|
||||
debugNavMeshes.clear();
|
||||
const auto& areas = navigation.getAreas();
|
||||
float y = navigation.getFloorY() + 0.02f;
|
||||
Eigen::Vector3f red(1.0f, 0.0f, 0.0f);
|
||||
|
||||
for (const auto& area : areas) {
|
||||
if (area.polygon.size() < 3) continue;
|
||||
navigationEditorNavMeshes.clear();
|
||||
const float y = navigation.getFloorY() + 0.02f;
|
||||
const Eigen::Vector3f red(1.0f, 0.0f, 0.0f);
|
||||
for (const auto& obs : navigation.getObstaclePolygons()) {
|
||||
if (obs.polygon.size() < 3) continue;
|
||||
VertexRenderStruct mesh;
|
||||
mesh.data = CreatePolygonFloor(area.polygon, y, red);
|
||||
mesh.data = CreatePolygonFloor(obs.polygon, y, red);
|
||||
mesh.RefreshVBO();
|
||||
debugNavMeshes.push_back(std::move(mesh));
|
||||
navigationEditorNavMeshes.push_back(std::move(mesh));
|
||||
}
|
||||
}
|
||||
|
||||
void Location::drawDebugNavigation()
|
||||
void Location::navigationEditorDrawNavigation()
|
||||
{
|
||||
renderer.shaderManager.PushShader("defaultColor");
|
||||
renderer.SetMatrix();
|
||||
for (const auto& mesh : debugNavMeshes) {
|
||||
for (const auto& mesh : navigationEditorNavMeshes) {
|
||||
renderer.DrawVertexRenderStruct(mesh);
|
||||
}
|
||||
renderer.shaderManager.PopShader();
|
||||
renderer.SetMatrix();
|
||||
}
|
||||
#endif
|
||||
|
||||
void Location::navigationEditorRebuildPointsMesh()
|
||||
{
|
||||
VertexDataStruct data;
|
||||
const Eigen::Vector3f yellow(1.0f, 1.0f, 0.0f);
|
||||
const float y = navigation.getFloorY() + 0.05f;
|
||||
const float s = 0.2f;
|
||||
|
||||
for (const auto& pt : navigationEditorPoints) {
|
||||
// Small upward-pointing equilateral triangle in the XZ plane
|
||||
Eigen::Vector3f v0(pt.x(), y, pt.z() - s * 1.15f);
|
||||
Eigen::Vector3f v1(pt.x() - s, y, pt.z() + s * 0.58f);
|
||||
Eigen::Vector3f v2(pt.x() + s, y, pt.z() + s * 0.58f);
|
||||
|
||||
data.PositionData.push_back(v0);
|
||||
data.PositionData.push_back(v1);
|
||||
data.PositionData.push_back(v2);
|
||||
data.ColorData.push_back(yellow);
|
||||
data.ColorData.push_back(yellow);
|
||||
data.ColorData.push_back(yellow);
|
||||
}
|
||||
|
||||
navigationEditorPointsMesh.data = std::move(data);
|
||||
navigationEditorPointsMesh.RefreshVBO();
|
||||
}
|
||||
|
||||
void Location::navigationEditorDrawPoints()
|
||||
{
|
||||
if (navigationEditorPoints.empty()) return;
|
||||
renderer.shaderManager.PushShader("defaultColor");
|
||||
renderer.SetMatrix();
|
||||
renderer.DrawVertexRenderStruct(navigationEditorPointsMesh);
|
||||
renderer.shaderManager.PopShader();
|
||||
renderer.SetMatrix();
|
||||
}
|
||||
|
||||
void Location::navigationEditorHandleLeftClick(const Eigen::Vector3f& hit, bool ctrlHeld)
|
||||
{
|
||||
if (ctrlHeld) {
|
||||
const float removeRadius = 1.0f;
|
||||
for (auto it = navigationEditorPoints.begin(); it != navigationEditorPoints.end(); ++it) {
|
||||
const float dx = it->x() - hit.x();
|
||||
const float dz = it->z() - hit.z();
|
||||
if (dx * dx + dz * dz <= removeRadius * removeRadius) {
|
||||
navigationEditorPoints.erase(it);
|
||||
navigationEditorRebuildPointsMesh();
|
||||
std::cout << "[NAV_EDITOR] Removed point, " << navigationEditorPoints.size() << " remaining\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
std::cout << "[NAV_EDITOR] No point found within " << removeRadius << " units of click\n";
|
||||
} else {
|
||||
navigationEditorPoints.push_back(hit);
|
||||
navigationEditorRebuildPointsMesh();
|
||||
std::cout << "[NAV_EDITOR] Added point (" << hit.x() << ", " << hit.z()
|
||||
<< "), total: " << navigationEditorPoints.size() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void Location::navigationEditorHandleRightClick()
|
||||
{
|
||||
if (navigationEditorPoints.size() < 3) {
|
||||
std::cout << "[NAV_EDITOR] Need at least 3 points to form a polygon (have "
|
||||
<< navigationEditorPoints.size() << "); clearing\n";
|
||||
navigationEditorPoints.clear();
|
||||
navigationEditorRebuildPointsMesh();
|
||||
return;
|
||||
}
|
||||
|
||||
PathFinder::ObstaclePolygon poly;
|
||||
poly.name = "editor_obstacle_" + std::to_string(++navigationEditorObstacleCounter);
|
||||
for (const auto& pt : navigationEditorPoints) {
|
||||
poly.polygon.emplace_back(pt.x(), pt.z());
|
||||
}
|
||||
|
||||
navigation.addObstaclePolygon(poly);
|
||||
std::cout << "[NAV_EDITOR] Added obstacle '" << poly.name << "' with "
|
||||
<< poly.polygon.size() << " vertices\n";
|
||||
|
||||
// Add a red mesh for the new obstacle polygon so it's visible immediately.
|
||||
{
|
||||
const float y = navigation.getFloorY() + 0.02f;
|
||||
const Eigen::Vector3f red(1.0f, 0.0f, 0.0f);
|
||||
VertexRenderStruct mesh;
|
||||
mesh.data = CreatePolygonFloor(poly.polygon, y, red);
|
||||
mesh.RefreshVBO();
|
||||
navigationEditorNavMeshes.push_back(std::move(mesh));
|
||||
}
|
||||
|
||||
navigationEditorPoints.clear();
|
||||
navigationEditorRebuildPointsMesh();
|
||||
}
|
||||
|
||||
void Location::navigationEditorSave()
|
||||
{
|
||||
std::string filename;
|
||||
for (int i = 1; ; ++i) {
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "saved_mesh%03d.json", i);
|
||||
filename = buf;
|
||||
if (!std::filesystem::exists(filename)) break;
|
||||
}
|
||||
|
||||
if (navigation.saveConfig(filename)) {
|
||||
std::cout << "[NAV_EDITOR] Saved navigation config to: " << filename << "\n";
|
||||
} else {
|
||||
std::cerr << "[NAV_EDITOR] Failed to save to: " << filename << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void Location::navigationEditorReload()
|
||||
{
|
||||
setupNavigation(navigationEditorConfigPath);
|
||||
std::cout << "[NAV_EDITOR] Reloaded navigation from: " << navigationEditorConfigPath << "\n";
|
||||
}
|
||||
|
||||
|
||||
InteractiveObject* Location::raycastInteractiveObjects(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir) {
|
||||
@@ -483,9 +598,10 @@ namespace ZL
|
||||
|
||||
for (auto& tz : teleportZones) tz.draw(renderer, Environment::zoom, Environment::width, Environment::height);
|
||||
|
||||
#ifdef SHOW_PATH
|
||||
drawDebugNavigation();
|
||||
#endif
|
||||
if (navigationEditorMode) {
|
||||
navigationEditorDrawNavigation();
|
||||
navigationEditorDrawPoints();
|
||||
}
|
||||
|
||||
renderer.PopMatrix();
|
||||
|
||||
@@ -677,6 +793,12 @@ namespace ZL
|
||||
|
||||
for (auto& tz : teleportZones) tz.draw(renderer, Environment::zoom, Environment::width, Environment::height);
|
||||
#endif
|
||||
|
||||
if (navigationEditorMode) {
|
||||
navigationEditorDrawNavigation();
|
||||
navigationEditorDrawPoints();
|
||||
}
|
||||
|
||||
CheckGlError(__FILE__, __LINE__);
|
||||
|
||||
renderer.PopMatrix();
|
||||
@@ -954,6 +1076,16 @@ namespace ZL
|
||||
|
||||
Eigen::Vector3f rayDir = (camForward + camRight * (ndcX * aspect * tanHalfFov) + camUp * (ndcY * tanHalfFov)).normalized();
|
||||
|
||||
if (navigationEditorMode) {
|
||||
if (rayDir.y() < -0.001f) {
|
||||
const float t = -camPos.y() / rayDir.y();
|
||||
const Eigen::Vector3f hit = camPos + rayDir * t;
|
||||
const bool ctrlHeld = (SDL_GetModState() & KMOD_CTRL) != 0;
|
||||
navigationEditorHandleLeftClick(hit, ctrlHeld);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "[CLICK] Camera position: (" << camPos.x() << ", " << camPos.y() << ", " << camPos.z() << ")" << std::endl;
|
||||
std::cout << "[CLICK] Ray direction: (" << rayDir.x() << ", " << rayDir.y() << ", " << rayDir.z() << ")" << std::endl;
|
||||
|
||||
|
||||
Reference in new issue
Block a user