|
20 | 20 | */
|
21 | 21 |
|
22 | 22 | #include "navmesh.h"
|
23 |
| -#include "../common/detour/DetourNavMeshQuery.h" |
24 |
| -#include <float.h> |
25 |
| -#include <string.h> |
| 23 | +#include <cstring> |
26 | 24 | #include <iostream>
|
27 | 25 | #include <fstream>
|
28 |
| -#include "../common/utils.h" |
29 | 26 | #include "../common/tpzrand.h"
|
30 | 27 |
|
31 | 28 | const int8 CNavMesh::ERROR_NEARESTPOLY;
|
@@ -164,7 +161,6 @@ bool CNavMesh::load(const std::string& filename)
|
164 | 161 |
|
165 | 162 | void CNavMesh::outputError(uint32 status)
|
166 | 163 | {
|
167 |
| - |
168 | 164 | if (status & DT_WRONG_MAGIC)
|
169 | 165 | {
|
170 | 166 | ShowNavError("Detour wrong magic\n");
|
@@ -380,60 +376,121 @@ bool CNavMesh::validPosition(const position_t& position)
|
380 | 376 | return m_navMesh->isValidPolyRef(startRef);
|
381 | 377 | }
|
382 | 378 |
|
| 379 | +double CNavMesh::DistanceToWall(const position_t& start) |
| 380 | +{ |
| 381 | + dtStatus status; |
| 382 | + float spos[3]; |
| 383 | + ToDetourPos(&start, spos); |
| 384 | + float polyPickExt[3]; |
| 385 | + polyPickExt[0] = 30; |
| 386 | + polyPickExt[1] = 60; |
| 387 | + polyPickExt[2] = 30; |
| 388 | + float snearest[3]; |
| 389 | + dtQueryFilter filter; |
| 390 | + |
| 391 | + // include walking |
| 392 | + filter.setIncludeFlags(0xFFE1); |
| 393 | + // exclude swim,jump,door |
| 394 | + filter.setExcludeFlags(0xE); |
| 395 | + |
| 396 | + dtPolyRef startRef; |
| 397 | + status = m_navMeshQuery.findNearestPoly(spos, polyPickExt, &filter, &startRef, snearest); |
| 398 | + if (dtStatusFailed(status)) |
| 399 | + { |
| 400 | + ShowNavError("CNavMesh::DistanceToWall findNearestPoly failed (%f, %f, %f) (%u)\n", spos[0], spos[1], spos[2], m_zoneID); |
| 401 | + outputError(status); |
| 402 | + return 0.0; |
| 403 | + } |
| 404 | + |
| 405 | + float distanceToWall = 0.0f; |
| 406 | + float hitPos[3]; |
| 407 | + float hitNormal[3]; |
| 408 | + int npolys; |
| 409 | + status = m_navMeshQuery.findDistanceToWall(startRef, snearest, 100.0f, &filter, &distanceToWall, hitPos, hitNormal); |
| 410 | + if (dtStatusFailed(status)) |
| 411 | + { |
| 412 | + ShowNavError("CNavMesh::DistanceToWall findDistanceToWall failed (%f, %f, %f) (%u)\n", spos[0], spos[1], spos[2], m_zoneID); |
| 413 | + outputError(status); |
| 414 | + return 0.0; |
| 415 | + } |
| 416 | + |
| 417 | + return static_cast<double>(distanceToWall); |
| 418 | +} |
| 419 | + |
| 420 | +// Recast Detour Docs: |
| 421 | +// Casts a 'walkability' ray along the surface of the navigation mesh from the start position toward the end position. |
| 422 | +// Note: This is not a point-to-point in 3D space calculation, it is 2D across the navmesh! |
383 | 423 | bool CNavMesh::raycast(const position_t& start, const position_t& end)
|
384 | 424 | {
|
385 | 425 | if (start.x == end.x && start.y == end.y && start.z == end.z)
|
| 426 | + { |
386 | 427 | return true;
|
387 |
| - dtStatus status; |
| 428 | + } |
388 | 429 |
|
| 430 | + dtStatus status; |
389 | 431 | float spos[3];
|
390 |
| - CNavMesh::ToDetourPos(&start, spos); |
| 432 | + ToDetourPos(&start, spos); |
391 | 433 |
|
392 | 434 | float epos[3];
|
393 |
| - CNavMesh::ToDetourPos(&end, epos); |
| 435 | + ToDetourPos(&end, epos); |
394 | 436 |
|
395 | 437 | float polyPickExt[3];
|
396 | 438 | polyPickExt[0] = 30;
|
397 | 439 | polyPickExt[1] = 60;
|
398 | 440 | polyPickExt[2] = 30;
|
399 | 441 |
|
400 | 442 | float snearest[3];
|
401 |
| - |
402 | 443 | dtQueryFilter filter;
|
403 |
| - filter.setIncludeFlags(0xffff); |
404 |
| - filter.setExcludeFlags(0); |
405 | 444 |
|
| 445 | + // include walking |
| 446 | + filter.setIncludeFlags(0xFFE1); |
| 447 | + // exclude swim,jump,door |
| 448 | + filter.setExcludeFlags(0xE); |
406 | 449 | dtPolyRef startRef;
|
407 | 450 |
|
408 | 451 | status = m_navMeshQuery.findNearestPoly(spos, polyPickExt, &filter, &startRef, snearest);
|
409 |
| - |
410 | 452 | if (dtStatusFailed(status))
|
411 | 453 | {
|
412 |
| - ShowNavError("CNavMesh::raycastPoint start point invalid (%f, %f, %f) (%u)\n", spos[0], spos[1], spos[2], m_zoneID); |
| 454 | + ShowNavError("CNavMesh::raycast start point invalid (%f, %f, %f) (%u)\n", spos[0], spos[1], spos[2], m_zoneID); |
413 | 455 | outputError(status);
|
414 |
| - return true; |
| 456 | + return false; |
415 | 457 | }
|
416 | 458 |
|
417 | 459 | if (!m_navMesh->isValidPolyRef(startRef))
|
418 | 460 | {
|
419 |
| - ShowNavError("CNavMesh::raycastPoint startRef is invalid (%f, %f, %f) (%u)\n", start.x, start.y, start.z, m_zoneID); |
420 |
| - return true; |
| 461 | + ShowNavError("CNavMesh::raycast startRef is invalid (%f, %f, %f) (%u)\n", start.x, start.y, start.z, m_zoneID); |
| 462 | + return false; |
421 | 463 | }
|
422 | 464 |
|
423 |
| - status = m_navMeshQuery.raycast(startRef, spos, epos, &filter, 0, &m_hit); |
424 |
| - |
425 |
| - if (dtStatusFailed(status)) |
| 465 | + // There is a tiny strip of walkable map at the very edge of walls that |
| 466 | + // a player can use, but is not part of the navmesh. For a point to be |
| 467 | + // raycasted to - it needs to be on the navmesh. This will check to |
| 468 | + // see if the player is "off-mesh" and raycast to the nearest "on-mesh" |
| 469 | + // point instead. |
| 470 | + if (DistanceToWall(end) <= 2.0) |
426 | 471 | {
|
427 |
| - ShowNavError("CNavMesh::raycastPoint raycast failed (%f, %f, %f)->(%f, %f, %f) (%u)\n", spos[0], spos[1], spos[2], epos[0], epos[1], epos[2], m_zoneID); |
428 |
| - outputError(status); |
429 |
| - return true; |
| 472 | + float closest[3]; |
| 473 | + status = m_navMeshQuery.closestPointOnPolyBoundary(startRef, epos, closest); |
| 474 | + if (dtStatusFailed(status)) |
| 475 | + { |
| 476 | + ShowNavError("CNavMesh::raycast closestPointOnPolyBoundary failed (%u)\n", m_zoneID); |
| 477 | + outputError(status); |
| 478 | + return false; |
| 479 | + } |
| 480 | + |
| 481 | + std::memcpy(epos, closest, sizeof(float) * 3); |
430 | 482 | }
|
431 | 483 |
|
432 |
| - // no wall was hit |
433 |
| - if (m_hit.t == FLT_MAX) |
| 484 | + float t = 0; |
| 485 | + float hitNormal[3]; |
| 486 | + int npolys = 0; |
| 487 | + status = m_navMeshQuery.raycast(startRef, spos, epos, &filter, &t, hitNormal, m_raycastVisitedPolys, &npolys, MAX_RAYCAST_POLYS); |
| 488 | + if (dtStatusFailed(status)) |
434 | 489 | {
|
435 |
| - return true; |
| 490 | + ShowNavError("CNavMesh::raycast raycast failed (%u)\n", m_zoneID); |
| 491 | + outputError(status); |
| 492 | + return false; |
436 | 493 | }
|
437 | 494 |
|
438 |
| - return false; |
| 495 | + return t > 1; |
439 | 496 | }
|
0 commit comments