feat(nav): 17.4 - a mesh has eight filters (a cost per kind of ground each) and every path, straight line and random point names the one it walks by, so a deer, a marmot and a person each take their own way over the same mesh; tested with a band of thicket walked round by the filter that dislikes it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f0485a20a8
commit
d4b6979426
10 changed files with 82 additions and 57 deletions
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
static dtPolyRef nav_poly_at(Nav *n, const float *p, float *on) {
|
||||
dtPolyRef r = 0;
|
||||
if (dtStatusFailed(n->query->findNearestPoly(p, n->ext, &n->filter, &r, on))) return 0;
|
||||
if (dtStatusFailed(n->query->findNearestPoly(p, n->ext, nav_filter(n, 0), &r, on))) return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -13,23 +13,23 @@ NAV_SHIM int nav_nearest(void *h, float x, float y, float z, float *out) {
|
|||
return nav_poly_at(static_cast<Nav *>(h), p, out) ? 1 : 0;
|
||||
}
|
||||
|
||||
// a cost per kind of ground (area 1..62): the filter every query uses
|
||||
NAV_SHIM void nav_area_cost(void *h, int area, float cost) {
|
||||
// filter f's cost for a kind of ground (area 1..62); a query names the filter it walks by
|
||||
NAV_SHIM void nav_area_cost(void *h, int f, int area, float cost) {
|
||||
Nav *n = static_cast<Nav *>(h);
|
||||
if (area > 0 && area < DT_MAX_AREAS) n->filter.setAreaCost(area, cost);
|
||||
if (f >= 0 && f < NAV_FILTERS && area > 0 && area < DT_MAX_AREAS) n->filters[f].setAreaCost(area, cost);
|
||||
}
|
||||
|
||||
// the corners of a path from one point to another, at most max of them, into out: the count, or
|
||||
// -1 when either end is off the mesh. One that cannot reach the end stops as near it as the mesh
|
||||
// allows, and nav_partial says so
|
||||
NAV_SHIM int nav_path(void *h, float sx, float sy, float sz, float ex, float ey, float ez, float *out, int max) {
|
||||
NAV_SHIM int nav_path(void *h, int f, float sx, float sy, float sz, float ex, float ey, float ez, float *out, int max) {
|
||||
Nav *n = static_cast<Nav *>(h);
|
||||
float s[3] = {sx, sy, sz}, e[3] = {ex, ey, ez}, so[3], eo[3];
|
||||
dtPolyRef a = nav_poly_at(n, s, so), b = nav_poly_at(n, e, eo);
|
||||
n->partial = 0;
|
||||
if (!a || !b) return -1;
|
||||
int np = 0;
|
||||
dtStatus st = n->query->findPath(a, b, so, eo, &n->filter, n->polys, &np, NAV_MAX_POLYS);
|
||||
dtStatus st = n->query->findPath(a, b, so, eo, nav_filter(n, f), n->polys, &np, NAV_MAX_POLYS);
|
||||
if (dtStatusFailed(st) || np == 0) return -1;
|
||||
if (dtStatusDetail(st, DT_PARTIAL_RESULT) || n->polys[np - 1] != b) n->partial = 1;
|
||||
float end[3];
|
||||
|
|
@ -42,13 +42,13 @@ NAV_SHIM int nav_path(void *h, float sx, float sy, float sz, float ex, float ey,
|
|||
NAV_SHIM int nav_partial(void *h) { return static_cast<Nav *>(h)->partial; }
|
||||
|
||||
// does the straight line from one point to another stay on the mesh? 1 yes, 0 no, -1 off it
|
||||
NAV_SHIM int nav_raycast(void *h, float sx, float sy, float sz, float ex, float ez) {
|
||||
NAV_SHIM int nav_raycast(void *h, int f, float sx, float sy, float sz, float ex, float ez) {
|
||||
Nav *n = static_cast<Nav *>(h);
|
||||
float s[3] = {sx, sy, sz}, so[3], e[3] = {ex, sy, ez}, t = 0, nrm[3];
|
||||
dtPolyRef a = nav_poly_at(n, s, so);
|
||||
if (!a) return -1;
|
||||
int np = 0;
|
||||
if (dtStatusFailed(n->query->raycast(a, so, e, &n->filter, &t, nrm, n->polys, &np, NAV_MAX_POLYS))) return -1;
|
||||
if (dtStatusFailed(n->query->raycast(a, so, e, nav_filter(n, f), &t, nrm, n->polys, &np, NAV_MAX_POLYS))) return -1;
|
||||
return t >= 1.0f ? 1 : 0;
|
||||
}
|
||||
|
||||
|
|
@ -60,13 +60,13 @@ static float nav_frand() {
|
|||
nav_rs = nav_rs * 1664525u + 1013904223u;
|
||||
return (float)(nav_rs >> 8) * (1.0f / 16777216.0f);
|
||||
}
|
||||
NAV_SHIM int nav_random_near(void *h, float x, float y, float z, float r, int seed, float *out) {
|
||||
NAV_SHIM int nav_random_near(void *h, int f, float x, float y, float z, float r, int seed, float *out) {
|
||||
Nav *n = static_cast<Nav *>(h);
|
||||
float p[3] = {x, y, z}, on[3];
|
||||
dtPolyRef start = nav_poly_at(n, p, on);
|
||||
if (!start) return 0;
|
||||
nav_rs = (unsigned int)seed * 2654435761u + 1u;
|
||||
dtPolyRef ref = 0;
|
||||
if (dtStatusFailed(n->query->findRandomPointAroundCircle(start, on, r, &n->filter, nav_frand, &ref, out))) return 0;
|
||||
if (dtStatusFailed(n->query->findRandomPointAroundCircle(start, on, r, nav_filter(n, f), nav_frand, &ref, out))) return 0;
|
||||
return ref ? 1 : 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,12 +19,13 @@
|
|||
namespace {
|
||||
const int NAV_MAX_POLYS = 512; // polygons a path may cross; a longer one is cut there
|
||||
const int NAV_MAX_NODES = 4096; // the search's open list
|
||||
const int NAV_FILTERS = 8; // costs per kind of ground: one set per kind of walker's taste
|
||||
|
||||
// a navmesh and the one query that walks it, with the scratch a path needs
|
||||
struct Nav {
|
||||
dtNavMesh *mesh = nullptr;
|
||||
dtNavMeshQuery *query = nullptr;
|
||||
dtQueryFilter filter;
|
||||
dtQueryFilter filters[NAV_FILTERS];
|
||||
float ext[3] = {2.0f, 4.0f, 2.0f}; // how far to look for the mesh around a point
|
||||
dtPolyRef polys[NAV_MAX_POLYS];
|
||||
int partial = 0; // the last path stopped short of its end
|
||||
|
|
@ -36,8 +37,10 @@ Nav *nav_open(dtNavMesh *mesh) {
|
|||
n->mesh = mesh;
|
||||
n->query = dtAllocNavMeshQuery();
|
||||
if (!n->query || dtStatusFailed(n->query->init(n->mesh, NAV_MAX_NODES))) { dtFreeNavMeshQuery(n->query); dtFreeNavMesh(n->mesh); delete n; return nullptr; }
|
||||
n->filter.setIncludeFlags(0xffff);
|
||||
n->filter.setExcludeFlags(0);
|
||||
for (int f = 0; f < NAV_FILTERS; ++f) {
|
||||
n->filters[f].setIncludeFlags(0xffff);
|
||||
n->filters[f].setExcludeFlags(0);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
Nav *nav_from(unsigned char *data, int size) {
|
||||
|
|
@ -45,6 +48,8 @@ Nav *nav_from(unsigned char *data, int size) {
|
|||
if (!mesh || dtStatusFailed(mesh->init(data, size, DT_TILE_FREE_DATA))) { dtFree(data); dtFreeNavMesh(mesh); return nullptr; }
|
||||
return nav_open(mesh);
|
||||
}
|
||||
// filter f, the first when f is out of range
|
||||
const dtQueryFilter *nav_filter(Nav *n, int f) { return &n->filters[f >= 0 && f < NAV_FILTERS ? f : 0]; }
|
||||
} // namespace
|
||||
|
||||
#include "nav_build.inl"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue