├── Makefile ├── README.md ├── lua-recastnavigation.cpp ├── recastnavigation.h └── srv_demo.navmesh /Makefile: -------------------------------------------------------------------------------- 1 | 2 | SKYNET_ROOT ?= ../../skynet 3 | include $(SKYNET_ROOT)/platform.mk 4 | 5 | PLAT ?= none 6 | TARGET ?= ../../luaclib/recastnavigation.so 7 | 8 | CXX=g++ 9 | 10 | ifeq ($(PLAT), macosx) 11 | CXXFLAGS = -g -O2 -pedantic -bundle -undefined dynamic_lookup -std=c++17 12 | else 13 | ifeq ($(PLAT), linux) 14 | CXXFLAGS = -g -O2 -shared -fPIC -std=c++17 15 | endif 16 | endif 17 | 18 | LUA_INC ?= $(SKYNET_ROOT)/3rd/lua/ 19 | 20 | RECAST_NAVIGATION_DIR = ../../thirdparty/recastnavigation 21 | 22 | DETOUR_INC = $(RECAST_NAVIGATION_DIR)/Detour/Include 23 | DETOUR_SRC = DetourAlloc.cpp DetourCommon.cpp DetourNavMesh.cpp DetourNavMeshBuilder.cpp \ 24 | DetourAssert.cpp DetourNavMeshQuery.cpp DetourNode.cpp 25 | 26 | RECAST_INC = $(RECAST_NAVIGATION_DIR)/Recast/Include 27 | RECAST_SRC = Recast.cpp RecastAlloc.cpp RecastArea.cpp RecastContour.cpp RecastFilter.cpp RecastLayers.cpp \ 28 | RecastAssert.cpp RecastMesh.cpp RecastMeshDetail.cpp RecastRasterization.cpp RecastRegion.cpp 29 | 30 | DETOUR_TILECACHE_INC = $(RECAST_NAVIGATION_DIR)/DetourTileCache/Include 31 | DETOUR_TILECACHE_SRC = DetourTileCache.cpp DetourTileCacheBuilder.cpp 32 | 33 | LRECAST_NAVIGATION = lua-recastnavigation.cpp 34 | 35 | .PHONY: all clean 36 | 37 | all: $(TARGET) 38 | 39 | $(TARGET): $(foreach v, $(DETOUR_SRC), $(RECAST_NAVIGATION_DIR)/Detour/Source/$(v)) \ 40 | $(foreach v, $(RECAST_SRC), $(RECAST_NAVIGATION_DIR)/Recast/Source/$(v)) \ 41 | $(foreach v, $(DETOUR_TILECACHE_SRC), $(RECAST_NAVIGATION_DIR)/DetourTileCache/Source/$(v)) \ 42 | $(foreach v, $(LRECAST_NAVIGATION), $(v)) 43 | $(CXX) $(CXXFLAGS) -o $@ $^ -I$(LUA_INC) -I$(RECAST_INC) -I$(DETOUR_INC) -I$(DETOUR_TILECACHE_INC) 44 | 45 | clean: 46 | rm -f *.o $(TARGET) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 请移步:[lua-navmesh](https://github.com/cloudfreexiao/pluto/tree/main/pluto/luaclib/lua-navmesh) 3 | 4 | 5 | Navigation 教程链接地址,navmesh文件的生成 6 | 7 | https://github.com/ketoo/NoahGameFrame/blob/master/NFComm/NFNavigationPlugin 8 | 9 | https://github.com/bluesky7290/NFrame_unity3d_nav 10 | 11 | 使用例子: 12 | ```lua 13 | local recastnavigation = require("recastnavigation") 14 | print("recastnavigation:", inspect(recastnavigation), "\n") 15 | 16 | local path = "./srv_demo.navmesh" 17 | local navmesh = recastnavigation.navmesh(1, path) 18 | print("navmesh:", inspect(navmesh), "\n") 19 | 20 | local res, path = navmesh:FindStraightPath(0,0,0,23,0,5) 21 | if res then 22 | print("navmesh FindStraightPath:", inspect(path), "\n") 23 | end 24 | 25 | navmesh = nil 26 | 27 | collectgarbage() 28 | 29 | while true do 30 | end 31 | ``` 32 | -------------------------------------------------------------------------------- /lua-recastnavigation.cpp: -------------------------------------------------------------------------------- 1 | #define LUA_LIB 2 | 3 | #ifdef __cplusplus 4 | extern "C" 5 | { 6 | #endif 7 | #include 8 | #include 9 | 10 | LUAMOD_API int luaopen_recastnavigation(lua_State *L); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | #include "recastnavigation.h" 17 | 18 | static void * 19 | check_userdata(lua_State *L, int idx) 20 | { 21 | void *ret = lua_touserdata(L, idx); 22 | luaL_argcheck(L, ret != NULL, idx, "Userdata should not be NULL"); 23 | return ret; 24 | } 25 | 26 | static void 27 | create_meta(lua_State *L, luaL_Reg *l, const char *name, lua_CFunction tostring, lua_CFunction gcfunc) 28 | { 29 | int n = 0; 30 | while (l[n].name) 31 | ++n; 32 | lua_newtable(L); 33 | lua_createtable(L, 0, n); 34 | int i; 35 | for (i = 0; i < n; i++) 36 | { 37 | lua_pushcfunction(L, l[i].func); 38 | lua_setfield(L, -2, l[i].name); 39 | } 40 | lua_setfield(L, -2, "__index"); 41 | lua_pushstring(L, name); 42 | lua_setfield(L, -2, "__metatable"); 43 | if (tostring) 44 | { 45 | lua_pushcfunction(L, tostring); 46 | lua_setfield(L, -2, "__tostring"); 47 | } 48 | 49 | if (gcfunc) 50 | { 51 | lua_pushcfunction(L, gcfunc); 52 | lua_setfield(L, -2, "__gc"); 53 | } 54 | } 55 | 56 | struct s_navigation 57 | { 58 | int64_t scene; 59 | RecastNavigationHandle *handle; 60 | }; 61 | 62 | static int 63 | lnew(lua_State *L) 64 | { 65 | int64_t scene = luaL_checknumber(L, 1); 66 | 67 | size_t l; 68 | const char *respath = luaL_checklstring(L, 2, &l); 69 | 70 | struct s_navigation *nav = (struct s_navigation *)lua_newuserdata(L, sizeof(struct s_navigation)); 71 | nav->scene = scene; 72 | nav->handle = NULL; 73 | 74 | nav->handle = RecastNavigationHandle::Create(respath); 75 | if (!nav->handle) 76 | { 77 | lua_pushnil(L); 78 | return 1; 79 | } 80 | 81 | lua_pushvalue(L, lua_upvalueindex(1)); 82 | lua_setmetatable(L, -2); 83 | return 1; 84 | } 85 | 86 | static int 87 | lrelease(lua_State *L) 88 | { 89 | struct s_navigation *nav = (struct s_navigation *)check_userdata(L, 1); 90 | printf("recastnavigation release [%lld]\n", nav->scene); 91 | 92 | if (nav->handle) 93 | { 94 | delete nav->handle; 95 | nav->handle = NULL; 96 | } 97 | else 98 | { 99 | printf("recastnavigation release handle is null"); 100 | } 101 | return 0; 102 | } 103 | 104 | static int 105 | lFindStraightPath(lua_State *L) 106 | { 107 | struct s_navigation *nav = (struct s_navigation *)check_userdata(L, 1); 108 | float start_x = luaL_checknumber(L, 2); 109 | float start_y = luaL_checknumber(L, 3); 110 | float start_z = luaL_checknumber(L, 4); 111 | 112 | float end_x = luaL_checknumber(L, 5); 113 | float end_y = luaL_checknumber(L, 6); 114 | float end_z = luaL_checknumber(L, 7); 115 | 116 | NFVector3 start(start_x, start_y, start_z); 117 | NFVector3 end(end_x, end_y, end_z); 118 | 119 | std::vector paths; 120 | int pos = nav->handle->FindStraightPath(start, end, paths); 121 | if (pos <= 0) 122 | { 123 | lua_pushboolean(L, false); 124 | return 1; 125 | } 126 | lua_pushboolean(L, true); 127 | lua_newtable(L); 128 | for (size_t i = 0; i < paths.size(); i++) 129 | { 130 | lua_createtable(L, 0, 3); 131 | lua_pushinteger(L, paths[i].X()); 132 | lua_rawseti(L, -2, 1); 133 | lua_pushinteger(L, paths[i].Y()); 134 | lua_rawseti(L, -2, 2); 135 | lua_pushinteger(L, paths[i].Z()); 136 | lua_rawseti(L, -2, 3); 137 | 138 | lua_rawseti(L, -2, i + 1); 139 | } 140 | return 2; 141 | } 142 | 143 | static int 144 | lFindRandomPointAroundCircle(lua_State *L) 145 | { 146 | struct s_navigation *nav = (struct s_navigation *)check_userdata(L, 1); 147 | float center_x = luaL_checknumber(L, 2); 148 | float center_y = luaL_checknumber(L, 3); 149 | float center_z = luaL_checknumber(L, 4); 150 | 151 | int max_points = luaL_checknumber(L, 5); 152 | float maxRadius = luaL_checknumber(L, 6); 153 | 154 | NFVector3 center(center_x, center_y, center_z); 155 | std::vector paths; 156 | 157 | int size = nav->handle->FindRandomPointAroundCircle(center, paths, max_points, maxRadius); 158 | if (size <= 0) 159 | { 160 | lua_pushboolean(L, false); 161 | return 1; 162 | } 163 | 164 | lua_pushboolean(L, true); 165 | 166 | lua_newtable(L); 167 | for (size_t i = 0; i < paths.size(); i++) 168 | { 169 | lua_newtable(L); 170 | lua_createtable(L, 0, 3); 171 | lua_pushinteger(L, paths[i].X()); 172 | lua_rawseti(L, -2, 1); 173 | lua_pushinteger(L, paths[i].Y()); 174 | lua_rawseti(L, -2, 2); 175 | lua_pushinteger(L, paths[i].Z()); 176 | lua_rawseti(L, -2, 3); 177 | 178 | lua_rawseti(L, -2, i + 1); 179 | } 180 | 181 | return 2; 182 | } 183 | 184 | static int 185 | lRaycast(lua_State *L) 186 | { 187 | struct s_navigation *nav = (struct s_navigation *)check_userdata(L, 1); 188 | float start_x = luaL_checknumber(L, 2); 189 | float start_y = luaL_checknumber(L, 3); 190 | float start_z = luaL_checknumber(L, 4); 191 | 192 | float end_x = luaL_checknumber(L, 5); 193 | float end_y = luaL_checknumber(L, 6); 194 | float end_z = luaL_checknumber(L, 7); 195 | 196 | NFVector3 start(start_x, start_y, start_z); 197 | NFVector3 end(end_x, end_y, end_z); 198 | 199 | std::vector hitPointVec; 200 | int res = nav->handle->Raycast(start, end, hitPointVec); 201 | lua_pushinteger(L, res); 202 | lua_newtable(L); 203 | for (size_t i = 0; i < hitPointVec.size(); i++) 204 | { 205 | lua_createtable(L, 0, 3); 206 | lua_pushinteger(L, hitPointVec[i].X()); 207 | lua_rawseti(L, -2, 1); 208 | lua_pushinteger(L, hitPointVec[i].Y()); 209 | lua_rawseti(L, -2, 2); 210 | lua_pushinteger(L, hitPointVec[i].Z()); 211 | lua_rawseti(L, -2, 3); 212 | 213 | lua_rawseti(L, -2, i + 1); 214 | } 215 | return 2; 216 | } 217 | 218 | static void 219 | lnavmesh(lua_State *L) 220 | { 221 | luaL_Reg l[] = { 222 | {"FindStraightPath", lFindStraightPath}, 223 | {"FindRandomPointAroundCircle", lFindRandomPointAroundCircle}, 224 | {"Raycast", lRaycast}, 225 | {NULL, NULL}, 226 | }; 227 | create_meta(L, l, "navmesh", NULL, lrelease); 228 | lua_pushcclosure(L, lnew, 1); 229 | } 230 | 231 | LUAMOD_API int 232 | luaopen_recastnavigation(lua_State *L) 233 | { 234 | luaL_checkversion(L); 235 | lua_newtable(L); 236 | 237 | lnavmesh(L); 238 | lua_setfield(L, -2, "navmesh"); 239 | 240 | return 1; 241 | } -------------------------------------------------------------------------------- /recastnavigation.h: -------------------------------------------------------------------------------- 1 | #ifndef _RECASTNAVIGATION_H_ 2 | #define _RECASTNAVIGATION_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "DetourNavMeshBuilder.h" 9 | #include "DetourNavMeshQuery.h" 10 | #include "DetourCommon.h" 11 | #include "DetourNavMesh.h" 12 | 13 | // https://github.com/ketoo/NoahGameFrame/blob/master/NFComm/NFNavigationPlugin 14 | 15 | /** 安全的释放一个指针内存 */ 16 | #define SAFE_RELEASE(i) \ 17 | if (i) \ 18 | { \ 19 | delete i; \ 20 | i = NULL; \ 21 | } 22 | 23 | /** 安全的释放一个指针数组内存 */ 24 | #define SAFE_RELEASE_ARRAY(i) \ 25 | if (i) \ 26 | { \ 27 | delete[] i; \ 28 | i = NULL; \ 29 | } 30 | 31 | // Returns a random number [0..1) 32 | static float frand() 33 | { 34 | return (float)rand() / (float)RAND_MAX; 35 | } 36 | 37 | struct NavMeshSetHeader 38 | { 39 | int version; 40 | int tileCount; 41 | dtNavMeshParams params; 42 | }; 43 | 44 | struct NavMeshTileHeader 45 | { 46 | dtTileRef tileRef; 47 | int dataSize; 48 | }; 49 | 50 | class NFVector3 51 | { 52 | private: 53 | float x, y, z; 54 | void InitData() 55 | { 56 | x = 0.0f; 57 | y = 0.0f; 58 | z = 0.0f; 59 | } 60 | 61 | public: 62 | // construction 63 | NFVector3() 64 | { 65 | InitData(); 66 | } 67 | 68 | NFVector3(float x, float y, float z) 69 | { 70 | this->x = x; 71 | this->y = y; 72 | this->z = z; 73 | } 74 | 75 | NFVector3(float coordinate[3]) 76 | { 77 | this->x = coordinate[0]; 78 | this->y = coordinate[1]; 79 | this->z = coordinate[2]; 80 | } 81 | 82 | NFVector3(double coordinate[3]) 83 | { 84 | this->x = (float)coordinate[0]; 85 | this->y = (float)coordinate[1]; 86 | this->z = (float)coordinate[2]; 87 | } 88 | 89 | NFVector3(const NFVector3 &v) 90 | { 91 | this->x = v.x; 92 | this->y = v.y; 93 | this->z = v.z; 94 | } 95 | 96 | //---------------------------------------------------------------------------- 97 | bool operator<(const NFVector3 &v) const 98 | { 99 | return this->Length() < v.Length(); 100 | } 101 | 102 | bool operator>(const NFVector3 &v) const 103 | { 104 | return this->Length() > v.Length(); 105 | } 106 | 107 | NFVector3 &operator=(const NFVector3 &v) 108 | { 109 | this->x = v.x; 110 | this->y = v.y; 111 | this->z = v.z; 112 | 113 | return *this; 114 | } 115 | 116 | bool operator==(const NFVector3 &v) const 117 | { 118 | return std::abs(this->x - v.x) < 0.001f && std::abs(this->y - v.y) < 0.001f && std::abs(this->z - v.z) < 0.001f; 119 | } 120 | 121 | bool operator!=(const NFVector3 &v) const 122 | { 123 | return std::abs(this->x - v.x) >= 0.001f || std::abs(this->y - v.y) >= 0.001f || std::abs(this->z - v.z) >= 0.001f; 124 | } 125 | 126 | //---------------------------------------------------------------------------- 127 | // Arithmetic Operations 128 | NFVector3 operator+(const NFVector3 &v) const 129 | { 130 | NFVector3 xV; 131 | 132 | xV.x = this->x + v.x; 133 | xV.y = this->y + v.y; 134 | xV.z = this->z + v.z; 135 | return xV; 136 | } 137 | 138 | NFVector3 operator-(const NFVector3 &v) const 139 | { 140 | NFVector3 xV; 141 | 142 | xV.x = this->x - v.x; 143 | xV.y = this->y - v.y; 144 | xV.z = this->z - v.z; 145 | return xV; 146 | } 147 | 148 | NFVector3 operator-() const 149 | { 150 | return NFVector3(-x, -y, -z); 151 | } 152 | 153 | NFVector3 operator*(float s) const 154 | { 155 | return NFVector3(x * s, y * s, z * s); 156 | } 157 | 158 | NFVector3 operator/(float s) const 159 | { 160 | if (std::abs(s) > 0.001f) 161 | { 162 | return NFVector3(x / s, y / s, z / s); 163 | } 164 | 165 | return Zero(); 166 | } 167 | 168 | //---------------------------------------------------------------------------- 169 | // Arithmetic Updates 170 | NFVector3 &operator+=(const NFVector3 &v) 171 | { 172 | x += v.x; 173 | y += v.y; 174 | z += v.z; 175 | return *this; 176 | } 177 | 178 | NFVector3 &operator-=(const NFVector3 &v) 179 | { 180 | x -= v.x; 181 | y -= v.y; 182 | z -= v.z; 183 | return *this; 184 | } 185 | 186 | NFVector3 &operator*=(float s) 187 | { 188 | x *= s; 189 | y *= s; 190 | z *= s; 191 | return *this; 192 | } 193 | 194 | NFVector3 operator/=(float s) 195 | { 196 | return NFVector3(x / s, y / s, z / s); 197 | } 198 | 199 | //---------------------------------------------------------------------------- 200 | float X() const 201 | { 202 | return this->x; 203 | } 204 | 205 | float Y() const 206 | { 207 | return this->y; 208 | } 209 | 210 | float Z() const 211 | { 212 | return this->z; 213 | } 214 | 215 | void SetX(float x) 216 | { 217 | this->x = x; 218 | } 219 | 220 | void SetY(float y) 221 | { 222 | this->y = y; 223 | } 224 | 225 | void SetZ(float z) 226 | { 227 | this->z = z; 228 | } 229 | 230 | //---------------------------------------------------------------------------- 231 | bool IsZero() const 232 | { 233 | return std::abs(x) < 0.001f && std::abs(y) < 0.001f && std::abs(z) < 0.001f; 234 | } 235 | //---------------------------------------------------------------------------- 236 | inline float SquaredMagnitude() const 237 | { 238 | return x * x + y * y + z * z; 239 | } 240 | 241 | //---------------------------------------------------------------------------- 242 | inline float SquaredLength() const 243 | { 244 | return SquaredMagnitude(); 245 | } 246 | 247 | //---------------------------------------------------------------------------- 248 | inline float Magnitude() const 249 | { 250 | return sqrtf(x * x + y * y + z * z); 251 | } 252 | 253 | //---------------------------------------------------------------------------- 254 | inline float Length() const 255 | { 256 | return Magnitude(); 257 | } 258 | 259 | //---------------------------------------------------------------------------- 260 | inline NFVector3 Direction() const 261 | { 262 | if (this->IsZero()) 263 | { 264 | return Zero(); 265 | } 266 | 267 | float lenSquared = SquaredMagnitude(); 268 | float invSqrt = 1.0f / sqrtf(lenSquared); 269 | return NFVector3(x * invSqrt, y * invSqrt, z * invSqrt); 270 | } 271 | 272 | //---------------------------------------------------------------------------- 273 | inline NFVector3 Normalized() const 274 | { 275 | return Direction(); 276 | } 277 | 278 | //---------------------------------------------------------------------------- 279 | float Distance(const NFVector3 &v) const 280 | { 281 | NFVector3 vX = *this - v; 282 | return vX.Length(); 283 | } 284 | 285 | // Special values. 286 | inline static const NFVector3 &Zero() 287 | { 288 | static NFVector3 v(0, 0, 0); 289 | return v; 290 | } 291 | inline static const NFVector3 &One() 292 | { 293 | static NFVector3 v(1, 1, 1); 294 | return v; 295 | } 296 | inline static const NFVector3 &UnitX() 297 | { 298 | static NFVector3 v(1, 0, 0); 299 | return v; 300 | } 301 | inline static const NFVector3 &UnitY() 302 | { 303 | static NFVector3 v(0, 1, 0); 304 | return v; 305 | } 306 | inline static const NFVector3 &UnitZ() 307 | { 308 | static NFVector3 v(0, 0, 1); 309 | return v; 310 | } 311 | }; 312 | 313 | class RecastNavigationHandle 314 | { 315 | public: 316 | static const int NAV_ERROR = -1; 317 | 318 | static const int MAX_POLYS = 256; 319 | static const int NAV_ERROR_NEARESTPOLY = -2; 320 | 321 | static const long RCN_NAVMESH_VERSION = 1; 322 | static const int INVALID_NAVMESH_POLYREF = 0; 323 | 324 | struct NavmeshLayer 325 | { 326 | dtNavMesh *pNavmesh; 327 | dtNavMeshQuery *pNavmeshQuery; 328 | }; 329 | 330 | public: 331 | RecastNavigationHandle(){}; 332 | 333 | virtual ~RecastNavigationHandle() 334 | { 335 | dtFreeNavMesh(navmeshLayer.pNavmesh); 336 | dtFreeNavMeshQuery(navmeshLayer.pNavmeshQuery); 337 | }; 338 | 339 | int FindStraightPath(const NFVector3 &start, const NFVector3 &end, std::vector &paths) 340 | { 341 | dtNavMeshQuery *navmeshQuery = navmeshLayer.pNavmeshQuery; 342 | 343 | float spos[3]; 344 | spos[0] = start.X(); 345 | spos[1] = start.Y(); 346 | spos[2] = start.Z(); 347 | 348 | float epos[3]; 349 | epos[0] = end.X(); 350 | epos[1] = end.Y(); 351 | epos[2] = end.Z(); 352 | 353 | dtQueryFilter filter; 354 | filter.setIncludeFlags(0xffff); 355 | filter.setExcludeFlags(0); 356 | 357 | const float extents[3] = {2.f, 4.f, 2.f}; 358 | 359 | dtPolyRef startRef = INVALID_NAVMESH_POLYREF; 360 | dtPolyRef endRef = INVALID_NAVMESH_POLYREF; 361 | 362 | float startNearestPt[3]; 363 | float endNearestPt[3]; 364 | navmeshQuery->findNearestPoly(spos, extents, &filter, &startRef, startNearestPt); 365 | navmeshQuery->findNearestPoly(epos, extents, &filter, &endRef, endNearestPt); 366 | 367 | if (!startRef || !endRef) 368 | { 369 | //debuf_msg("NavMeshHandle::findStraightPath({%s}): Could not find any nearby poly's ({%d}, {%d})\n", resPath.c_str(), startRef, endRef); 370 | return NAV_ERROR_NEARESTPOLY; 371 | } 372 | 373 | dtPolyRef polys[MAX_POLYS]; 374 | int npolys; 375 | float straightPath[MAX_POLYS * 3]; 376 | unsigned char straightPathFlags[MAX_POLYS]; 377 | dtPolyRef straightPathPolys[MAX_POLYS]; 378 | int nstraightPath; 379 | int pos = 0; 380 | 381 | navmeshQuery->findPath(startRef, endRef, startNearestPt, endNearestPt, &filter, polys, &npolys, MAX_POLYS); 382 | nstraightPath = 0; 383 | 384 | if (npolys) 385 | { 386 | float epos1[3]; 387 | dtVcopy(epos1, endNearestPt); 388 | 389 | if (polys[npolys - 1] != endRef) 390 | navmeshQuery->closestPointOnPoly(polys[npolys - 1], endNearestPt, epos1, 0); 391 | 392 | navmeshQuery->findStraightPath(startNearestPt, endNearestPt, polys, npolys, straightPath, straightPathFlags, straightPathPolys, &nstraightPath, MAX_POLYS); 393 | 394 | NFVector3 currpos; 395 | for (int i = 0; i < nstraightPath * 3;) 396 | { 397 | currpos.SetX(straightPath[i++]); 398 | currpos.SetY(straightPath[i++]); 399 | currpos.SetZ(straightPath[i++]); 400 | paths.push_back(currpos); 401 | pos++; 402 | } 403 | } 404 | 405 | return pos; 406 | } 407 | 408 | int FindRandomPointAroundCircle(const NFVector3 ¢erPos, std::vector &points, int maxPoints, float maxRadius) 409 | { 410 | dtNavMeshQuery *navmeshQuery = navmeshLayer.pNavmeshQuery; 411 | 412 | dtQueryFilter filter; 413 | filter.setIncludeFlags(0xffff); 414 | filter.setExcludeFlags(0); 415 | 416 | if (maxRadius <= 0.0001f) 417 | { 418 | NFVector3 currpos; 419 | 420 | for (int i = 0; i < maxPoints; i++) 421 | { 422 | float pt[3]; 423 | dtPolyRef ref; 424 | dtStatus status = navmeshQuery->findRandomPoint(&filter, frand, &ref, pt); 425 | if (dtStatusSucceed(status)) 426 | { 427 | currpos.SetX(pt[0]); 428 | currpos.SetY(pt[1]); 429 | currpos.SetZ(pt[2]); 430 | 431 | points.push_back(currpos); 432 | } 433 | } 434 | 435 | return (int)points.size(); 436 | } 437 | 438 | const float extents[3] = {2.f, 4.f, 2.f}; 439 | 440 | dtPolyRef startRef = INVALID_NAVMESH_POLYREF; 441 | 442 | float spos[3]; 443 | spos[0] = centerPos.X(); 444 | spos[1] = centerPos.Y(); 445 | spos[2] = centerPos.Z(); 446 | 447 | float startNearestPt[3]; 448 | navmeshQuery->findNearestPoly(spos, extents, &filter, &startRef, startNearestPt); 449 | 450 | if (!startRef) 451 | { 452 | //debuf_msg("NavMeshHandle::findRandomPointAroundCircle({%s}): Could not find any nearby poly's ({%d})\n", resPath, startRef); 453 | return NAV_ERROR_NEARESTPOLY; 454 | } 455 | 456 | NFVector3 currpos; 457 | bool done = false; 458 | int itry = 0; 459 | 460 | while (itry++ < 3 && points.size() == 0) 461 | { 462 | maxPoints -= (int)points.size(); 463 | 464 | for (int i = 0; i < maxPoints; i++) 465 | { 466 | float pt[3]; 467 | dtPolyRef ref; 468 | dtStatus status = navmeshQuery->findRandomPointAroundCircle(startRef, spos, maxRadius, &filter, frand, &ref, pt); 469 | 470 | if (dtStatusSucceed(status)) 471 | { 472 | done = true; 473 | currpos.SetX(pt[0]); 474 | currpos.SetY(pt[1]); 475 | currpos.SetZ(pt[2]); 476 | 477 | NFVector3 v = centerPos - currpos; 478 | float dist_len = v.Length(); 479 | if (dist_len > maxRadius) 480 | continue; 481 | 482 | points.push_back(currpos); 483 | } 484 | } 485 | 486 | if (!done) 487 | break; 488 | } 489 | 490 | return (int)points.size(); 491 | } 492 | 493 | int Raycast(const NFVector3 &start, const NFVector3 &end, std::vector &hitPointVec) 494 | { 495 | dtNavMeshQuery *navmeshQuery = navmeshLayer.pNavmeshQuery; 496 | 497 | float hitPoint[3]; 498 | 499 | float spos[3]; 500 | spos[0] = start.X(); 501 | spos[1] = start.Y(); 502 | spos[2] = start.Z(); 503 | 504 | float epos[3]; 505 | epos[0] = end.X(); 506 | epos[1] = end.Y(); 507 | epos[2] = end.Z(); 508 | 509 | dtQueryFilter filter; 510 | filter.setIncludeFlags(0xffff); 511 | filter.setExcludeFlags(0); 512 | 513 | const float extents[3] = {2.f, 4.f, 2.f}; 514 | 515 | dtPolyRef startRef = INVALID_NAVMESH_POLYREF; 516 | 517 | float nearestPt[3]; 518 | navmeshQuery->findNearestPoly(spos, extents, &filter, &startRef, nearestPt); 519 | 520 | if (!startRef) 521 | { 522 | return NAV_ERROR_NEARESTPOLY; 523 | } 524 | 525 | float t = 0; 526 | float hitNormal[3]; 527 | memset(hitNormal, 0, sizeof(hitNormal)); 528 | 529 | dtPolyRef polys[MAX_POLYS]; 530 | int npolys; 531 | 532 | navmeshQuery->raycast(startRef, spos, epos, &filter, &t, hitNormal, polys, &npolys, MAX_POLYS); 533 | 534 | if (t > 1) 535 | { 536 | // no hit 537 | return NAV_ERROR; 538 | } 539 | else 540 | { 541 | // Hit 542 | hitPoint[0] = spos[0] + (epos[0] - spos[0]) * t; 543 | hitPoint[1] = spos[1] + (epos[1] - spos[1]) * t; 544 | hitPoint[2] = spos[2] + (epos[2] - spos[2]) * t; 545 | if (npolys) 546 | { 547 | float h = 0; 548 | navmeshQuery->getPolyHeight(polys[npolys - 1], hitPoint, &h); 549 | hitPoint[1] = h; 550 | } 551 | } 552 | 553 | hitPointVec.push_back(NFVector3(hitPoint[0], hitPoint[1], hitPoint[2])); 554 | return 1; 555 | } 556 | 557 | static RecastNavigationHandle *Create(std::string resPath) 558 | { 559 | FILE *fp = fopen(resPath.c_str(), "rb"); 560 | if (!fp) 561 | { 562 | printf("RecastNavigationHandle::create: open({%s}) is error!\n", resPath.c_str()); 563 | return NULL; 564 | } 565 | 566 | printf("RecastNavigationHandle::create: ({%s}), layer={%d}\n", resPath.c_str(), 0); 567 | 568 | bool safeStorage = true; 569 | int pos = 0; 570 | int size = sizeof(NavMeshSetHeader); 571 | 572 | fseek(fp, 0, SEEK_END); 573 | size_t flen = ftell(fp); 574 | fseek(fp, 0, SEEK_SET); 575 | 576 | uint8_t *data = new uint8_t[flen]; 577 | if (data == NULL) 578 | { 579 | printf("RecastNavigationHandle::create: open({%s}), memory(size={%d}) error!\n", resPath.c_str(), (int)flen); 580 | 581 | fclose(fp); 582 | SAFE_RELEASE_ARRAY(data); 583 | return NULL; 584 | } 585 | 586 | size_t readsize = fread(data, 1, flen, fp); 587 | if (readsize != flen) 588 | { 589 | printf("RecastNavigationHandle::create: open({%s}), read(size={%d} != {%d}) error!\n", resPath.c_str(), (int)readsize, (int)flen); 590 | 591 | fclose(fp); 592 | SAFE_RELEASE_ARRAY(data); 593 | return NULL; 594 | } 595 | 596 | if (readsize < sizeof(NavMeshSetHeader)) 597 | { 598 | printf("RecastNavigationHandle::create: open({%s}), NavMeshSetHeader is error!\n", resPath.c_str()); 599 | 600 | fclose(fp); 601 | SAFE_RELEASE_ARRAY(data); 602 | return NULL; 603 | } 604 | 605 | NavMeshSetHeader header; 606 | memcpy(&header, data, size); 607 | 608 | pos += size; 609 | 610 | if (header.version != RecastNavigationHandle::RCN_NAVMESH_VERSION) 611 | { 612 | printf("NFNavigationHandle::create: navmesh version({%d}) is not match({%d})!\n", header.version, ((int)RecastNavigationHandle::RCN_NAVMESH_VERSION)); 613 | 614 | fclose(fp); 615 | SAFE_RELEASE_ARRAY(data); 616 | return NULL; 617 | } 618 | 619 | dtNavMesh *mesh = dtAllocNavMesh(); 620 | if (!mesh) 621 | { 622 | printf("NavMeshHandle::create: dtAllocNavMesh is failed!\n"); 623 | fclose(fp); 624 | SAFE_RELEASE_ARRAY(data); 625 | return NULL; 626 | } 627 | 628 | dtStatus status = mesh->init(&header.params); 629 | if (dtStatusFailed(status)) 630 | { 631 | printf("NFNavigationHandle::create: mesh init is error({%d})!\n", status); 632 | fclose(fp); 633 | SAFE_RELEASE_ARRAY(data); 634 | return NULL; 635 | } 636 | 637 | // Read tiles. 638 | bool success = true; 639 | for (int i = 0; i < header.tileCount; ++i) 640 | { 641 | NavMeshTileHeader tileHeader; 642 | size = sizeof(NavMeshTileHeader); 643 | memcpy(&tileHeader, &data[pos], size); 644 | pos += size; 645 | 646 | size = tileHeader.dataSize; 647 | if (!tileHeader.tileRef || !tileHeader.dataSize) 648 | { 649 | success = false; 650 | status = DT_FAILURE + DT_INVALID_PARAM; 651 | break; 652 | } 653 | 654 | unsigned char *tileData = 655 | (unsigned char *)dtAlloc(size, DT_ALLOC_PERM); 656 | if (!tileData) 657 | { 658 | success = false; 659 | status = DT_FAILURE + DT_OUT_OF_MEMORY; 660 | break; 661 | } 662 | memcpy(tileData, &data[pos], size); 663 | pos += size; 664 | 665 | status = mesh->addTile(tileData, size, (safeStorage ? DT_TILE_FREE_DATA : 0), tileHeader.tileRef, 0); 666 | 667 | if (dtStatusFailed(status)) 668 | { 669 | success = false; 670 | break; 671 | } 672 | } 673 | 674 | fclose(fp); 675 | SAFE_RELEASE_ARRAY(data); 676 | 677 | if (!success) 678 | { 679 | printf("NavMeshHandle::create: error({%d})!\n", status); 680 | dtFreeNavMesh(mesh); 681 | return NULL; 682 | } 683 | 684 | RecastNavigationHandle *pNavMeshHandle = new RecastNavigationHandle(); 685 | dtNavMeshQuery *pNavmeshQuery = new dtNavMeshQuery(); 686 | 687 | pNavmeshQuery->init(mesh, 1024); 688 | pNavMeshHandle->resPath = resPath; 689 | pNavMeshHandle->navmeshLayer.pNavmeshQuery = pNavmeshQuery; 690 | pNavMeshHandle->navmeshLayer.pNavmesh = mesh; 691 | 692 | uint32_t tileCount = 0; 693 | uint32_t nodeCount = 0; 694 | uint32_t polyCount = 0; 695 | uint32_t vertCount = 0; 696 | uint32_t triCount = 0; 697 | uint32_t triVertCount = 0; 698 | uint32_t dataSize = 0; 699 | 700 | const dtNavMesh *navmesh = mesh; 701 | for (int i = 0; i < navmesh->getMaxTiles(); ++i) 702 | { 703 | const dtMeshTile *tile = navmesh->getTile(i); 704 | if (!tile || !tile->header) 705 | continue; 706 | 707 | tileCount++; 708 | nodeCount += tile->header->bvNodeCount; 709 | polyCount += tile->header->polyCount; 710 | vertCount += tile->header->vertCount; 711 | triCount += tile->header->detailTriCount; 712 | triVertCount += tile->header->detailVertCount; 713 | dataSize += tile->dataSize; 714 | } 715 | 716 | printf("\t==> ----------------RecastNavigationHandle Create------------------------\n"); 717 | printf("\t==> resPath: {%s}\n", resPath.c_str()); 718 | printf("\t==> tiles loaded: {%d}\n", tileCount); 719 | printf("\t==> BVTree nodes: {%d}\n", nodeCount); 720 | printf("\t==> {%d} polygons ({%d} vertices)\n", polyCount, vertCount); 721 | printf("\t==> {%d} triangles ({%d} vertices)\n", triCount, triVertCount); 722 | printf("\t==> {%f:.2f} MB of data (not including pointers)\n", (((float)dataSize / sizeof(unsigned char)) / 1048576)); 723 | printf("\t==> ----------------RecastNavigationHandle Create------------------------\n"); 724 | 725 | return pNavMeshHandle; 726 | } 727 | 728 | NavmeshLayer navmeshLayer; 729 | std::string resPath; 730 | }; 731 | 732 | #endif -------------------------------------------------------------------------------- /srv_demo.navmesh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfreexiao/lua-recastnavigation/64e51b73fb700a73e048cc526fe4265e8273f36a/srv_demo.navmesh --------------------------------------------------------------------------------