8 #include <unordered_map>
9 #include <unordered_set>
28 using std::make_unique;
34 using std::unique_ptr;
35 using std::unordered_map;
36 using std::unordered_set;
56 PathFinding::PathFinding(
64 uint16_t skipOnCollisionTypeIds,
66 float flowMapStepSize,
67 float flowMapScaleActorBoundingVolumes
94 tuple<uint8_t, uint8_t, int, int, int, uint16_t, bool> cacheId;
95 if (flowMapRequest ==
true) {
96 cacheId = tuple<uint8_t, uint8_t, int, int, int, uint16_t, bool> {
97 static_cast<uint8_t
>(
stepSize * 10.0f),
98 static_cast<uint8_t
>(scaleActorBoundingVolumes * 10.0f),
99 static_cast<int>(Math::ceil(x /
stepSize)),
100 static_cast<int>(Math::ceil(y / 0.1f)),
101 static_cast<int>(Math::ceil(z /
stepSize)),
107 height = walkableCacheIt->second;
108 return height > -10000.0f;
112 if (flowMapRequest ==
true)
walkableCache[cacheId] = walkable ==
false?-10000.0f:height;
113 if (walkable ==
false)
return false;
114 return customTest ==
nullptr || customTest->
isWalkable(
this, x, height, z) ==
true;
117 bool PathFinding::isSlopeWalkableInternal(
float x,
float y,
float z,
float successorX,
float successorY,
float successorZ,
float stepSize,
float scaleActorBoundingVolumes,
bool flowMapRequest,
PathFindingCustomTest* customTest, uint16_t collisionTypeIds) {
125 float slopeAngle = 0.0f;
128 auto toVector =
Vector3(successorX, y, successorZ);
129 auto fromVector =
Vector3(x, y, z);
130 auto axis = toVector.clone().sub(fromVector);
131 auto center = axis.clone().scale(0.5f).add(fromVector).setY(y + 0.1f);
133 slopeAngle = Vector3::computeAngle(
139 tuple<uint8_t, uint8_t, int, int, int, uint16_t, int16_t> cacheId;
140 if (flowMapRequest ==
true) {
141 cacheId = tuple<uint8_t, uint8_t, int, int, int, uint16_t, int16_t> {
142 static_cast<uint8_t
>(
stepSize * 10.0f),
143 static_cast<uint8_t
>(scaleActorBoundingVolumes * 10.0f),
144 static_cast<int>(Math::ceil(x /
stepSize)),
145 static_cast<int>(Math::ceil(y / 0.1f)),
146 static_cast<int>(Math::ceil(z /
stepSize)),
148 static_cast<int16_t
>(slopeAngle),
152 auto height = walkableCacheIt->second;
161 slopeTestTransform.
update();
164 auto actorSlopeTestCollisionBody =
world->
getBody(
"tdme.pathfinding.actor.slopetest");
165 actorSlopeTestCollisionBody->
setTransform(slopeTestTransform);
168 vector<Body*> collidedRigidBodies;
170 if (flowMapRequest ==
true)
walkableCache[cacheId] = walkable ==
false?-10000.0f:0.0f;
174 bool PathFinding::isWalkable(
float x,
float y,
float z,
float& height,
float stepSize,
float scaleActorBoundingVolumes,
bool flowMapRequest, uint16_t collisionTypeIds,
bool ignoreStepUpMax) {
179 for (
auto i = 0; i <= 4; i++) {
181 for (
auto j = 0; j <= 4; j++) {
182 Vector3 actorPositionCandidate;
186 actorPositionCandidate.
set(_x, y, _z),
194 if (actorPosition.
getY() > height) height = actorPosition.
getY();
206 auto actorCollisionBody =
world->
getBody(
"tdme.pathfinding.actor");
210 vector<Body*> collidedRigidBodies;
212 return collision ==
false;
216 auto nodeId = node->
id;
219 stack<PathFindingNode*> successorNodes;
220 for (
auto z = -1; z <= 1; z++)
221 for (
auto x = -1; x <= 1; x++)
222 if ((z != 0 || x != 0) &&
224 (Math::abs(x) == 1 && Math::abs(z) == 1) ==
false)) {
225 auto successorX =
static_cast<float>(x) *
stepSize + (nodesToTestPtr !=
nullptr?
static_cast<float>(node->
x) *
stepSize:node->
position.
getX());
226 auto successorZ =
static_cast<float>(z) *
stepSize + (nodesToTestPtr !=
nullptr?
static_cast<float>(node->
z) *
stepSize:node->
position.
getZ());
227 if (nodesToTestPtr !=
nullptr) {
228 auto successorNodeId =
toIdInt(
233 if (nodesToTestPtr->find(successorNodeId) == nodesToTestPtr->end())
continue;
241 if (
equals(node, successorX, yHeight, successorZ)) {
247 successorNode->position =
Vector3(successorX, yHeight, successorZ);
248 successorNode->costsAll = 0.0f;
249 successorNode->costsReachPoint = 0.0f;
250 successorNode->costsEstimated = 0.0f;
251 successorNode->x = node->
x + x;
253 successorNode->z = node->
z + z;
259 successorNodes.push(successorNode);
264 while (successorNodes.empty() ==
false) {
265 auto successorNode = successorNodes.top();
272 auto openListNodeIt =
openNodes.find(successorNode->id);
274 openListNode = openListNodeIt->second;
278 if (openListNode !=
nullptr) {
283 successorNodes.pop();
291 auto closedListNodeIt =
closedNodes.find(successorNode->id);
293 closedListNode = closedListNodeIt->second;
297 if (closedListNode !=
nullptr) {
302 successorNodes.pop();
309 successorNode->hasPreviousNode =
true;
310 successorNode->previousNodeId = nodeId;
311 successorNode->costsReachPoint = successorCostsReachPoint;
313 successorNode->costsAll = successorNode->costsReachPoint + successorNode->costsEstimated;
316 if (openListNode !=
nullptr) {
323 if (closedListNode !=
nullptr) {
329 openNodes[successorNode->id] = successorNode;
332 successorNodes.pop();
346 float scaleActorBoundingVolumes,
347 const uint16_t collisionTypeIds,
348 vector<Vector3>& path,
349 int alternativeEndSteps,
350 int maxTriesOverride,
359 auto currentMaxTries = maxTriesOverride == -1?this->
maxTries:maxTriesOverride;
362 if (customTest !=
nullptr) customTest->
initialize();
368 auto actorBoundingVolume = make_unique<OrientedBoundingBox>(
370 OrientedBoundingBox::AABB_AXIS_X,
371 OrientedBoundingBox::AABB_AXIS_Y,
372 OrientedBoundingBox::AABB_AXIS_Z,
379 world->
addDynamicCollisionBody(
"tdme.pathfinding.actor", Body::COLLISION_TYPEID_RESERVED,
true, actorTransform, { actorBoundingVolume.get() });
382 auto actorBoundingVolumeSlopeTest = make_unique<OrientedBoundingBox>(
384 OrientedBoundingBox::AABB_AXIS_X,
385 OrientedBoundingBox::AABB_AXIS_Y,
386 OrientedBoundingBox::AABB_AXIS_Z,
389 world->
addDynamicCollisionBody(
"tdme.pathfinding.actor.slopetest", Body::COLLISION_TYPEID_RESERVED,
true, actorTransform, { actorBoundingVolumeSlopeTest.get() });
392 bool success =
false;
397 path.push_back(startPosition);
398 path.push_back(endPosition);
403 if (
VERBOSE ==
true)
Console::println(
"PathFinding::findPath(): end - start position < stepSizeLast! Exiting!");
404 path.push_back(startPosition);
405 float endYHeight = endPosition.
getY();
412 scaleActorBoundingVolumes,
416 path.push_back(startPosition);
418 path.push_back(endPosition);
425 auto endPositionIdx = 0;
428 if (success ==
false) {
430 auto forcedAlternativeEndSteps = 0;
433 vector<Vector3> startPositionCandidates;
434 vector<Vector3> endPositionCandidates;
437 auto sideVector = Vector3::computeCrossProduct(forwardVector,
Vector3(0.0f, 1.0f, 0.0f)).
setY(0.0f).
normalize();
442 endPositionCandidates.push_back(endPosition);
443 startPositionCandidates.push_back(startPosition);
447 auto forwardDistance = 0.0f;
449 while (
true ==
true) {
450 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(0.0f).add(forwardVector.clone().scale(-forwardDistance)).
add(endPosition));
451 i++;
if (i >= alternativeEndSteps)
break;
452 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(-sideDistance).add(forwardVector.clone().scale(-forwardDistance)).
add(endPosition));
453 i++;
if (i >= alternativeEndSteps)
break;
454 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(+sideDistance).add(forwardVector.clone().scale(-forwardDistance)).
add(endPosition));
455 i++;
if (i >= alternativeEndSteps)
break;
458 forwardDistance = 0.0f;
459 forwardVector.scale(-1.0f);
460 sideVector.scale(-1.0f);
461 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(0.0f).add(forwardVector.clone().scale(-forwardDistance)).
add(startPosition));
462 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(-sideDistance).add(forwardVector.clone().scale(-forwardDistance)).
add(startPosition));
463 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(+sideDistance).add(forwardVector.clone().scale(-forwardDistance)).
add(startPosition));
464 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(0.0f).add(forwardVector.clone().scale(forwardDistance)).
add(startPosition));
465 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(-sideDistance).add(forwardVector.clone().scale(forwardDistance)).
add(startPosition));
466 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(+sideDistance).add(forwardVector.clone().scale(forwardDistance)).
add(startPosition));
468 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(0.0f).add(forwardVector.clone().scale(-forwardDistance)).
add(startPosition));
469 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(-sideDistance).add(forwardVector.clone().scale(-forwardDistance)).
add(startPosition));
470 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(+sideDistance).add(forwardVector.clone().scale(-forwardDistance)).
add(startPosition));
471 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(0.0f).add(forwardVector.clone().scale(forwardDistance)).
add(startPosition));
472 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(-sideDistance).add(forwardVector.clone().scale(forwardDistance)).
add(startPosition));
473 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(+sideDistance).add(forwardVector.clone().scale(forwardDistance)).
add(startPosition));
475 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(0.0f).add(forwardVector.clone().scale(-forwardDistance)).
add(startPosition));
476 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(-sideDistance).add(forwardVector.clone().scale(-forwardDistance)).
add(startPosition));
477 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(+sideDistance).add(forwardVector.clone().scale(-forwardDistance)).
add(startPosition));
478 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(0.0f).add(forwardVector.clone().scale(forwardDistance)).
add(startPosition));
479 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(-sideDistance).add(forwardVector.clone().scale(forwardDistance)).
add(startPosition));
480 startPositionCandidates.push_back(
Vector3().set(sideVector).scale(+sideDistance).add(forwardVector.clone().scale(forwardDistance)).
add(startPosition));
482 if (currentMaxTries == 0) {
483 forcedAlternativeEndSteps = 27 * 2;
484 auto forwardDistance = 0.0f;
486 while (
true ==
true) {
487 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(0.0f).add(forwardVector.clone().scale(forwardDistance)).
add(endPosition));
488 i++;
if (i >= forcedAlternativeEndSteps)
break;
489 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(-0.3f).add(forwardVector.clone().scale(forwardDistance)).
add(endPosition));
490 i++;
if (i >= forcedAlternativeEndSteps)
break;
491 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(-0.2f).add(forwardVector.clone().scale(forwardDistance)).
add(endPosition));
492 i++;
if (i >= forcedAlternativeEndSteps)
break;
493 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(-0.1f).add(forwardVector.clone().scale(forwardDistance)).
add(endPosition));
494 i++;
if (i >= forcedAlternativeEndSteps)
break;
495 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(+0.1f).add(forwardVector.clone().scale(forwardDistance)).
add(endPosition));
496 i++;
if (i >= forcedAlternativeEndSteps)
break;
497 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(+0.2f).add(forwardVector.clone().scale(forwardDistance)).
add(endPosition));
498 i++;
if (i >= forcedAlternativeEndSteps)
break;
499 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(+0.3f).add(forwardVector.clone().scale(forwardDistance)).
add(endPosition));
500 i++;
if (i >= forcedAlternativeEndSteps)
break;
501 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(0.0f).add(forwardVector.clone().scale(-forwardDistance)).
add(endPosition));
502 i++;
if (i >= forcedAlternativeEndSteps)
break;
503 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(-0.3f).add(forwardVector.clone().scale(-forwardDistance)).
add(endPosition));
504 i++;
if (i >= forcedAlternativeEndSteps)
break;
505 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(-0.2f).add(forwardVector.clone().scale(-forwardDistance)).
add(endPosition));
506 i++;
if (i >= forcedAlternativeEndSteps)
break;
507 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(-0.1f).add(forwardVector.clone().scale(-forwardDistance)).
add(endPosition));
508 i++;
if (i >= forcedAlternativeEndSteps)
break;
509 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(+0.1f).add(forwardVector.clone().scale(-forwardDistance)).
add(endPosition));
510 i++;
if (i >= forcedAlternativeEndSteps)
break;
511 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(+0.2f).add(forwardVector.clone().scale(-forwardDistance)).
add(endPosition));
512 i++;
if (i >= forcedAlternativeEndSteps)
break;
513 endPositionCandidates.push_back(
Vector3().set(sideVector).scale(+0.3f).add(forwardVector.clone().scale(-forwardDistance)).
add(endPosition));
514 i++;
if (i >= forcedAlternativeEndSteps)
break;
515 forwardDistance+= 0.1f;
521 Vector3 startPositionComputed = startPosition;
522 for (
const auto& startPositionCandidate: startPositionCandidates) {
523 float startYHeight = startPositionCandidate.
getY();
525 startPositionCandidate.getX(),
526 startPositionCandidate.getY(),
527 startPositionCandidate.getZ(),
530 scaleActorBoundingVolumes,
536 "PathFinding::findPath(): Start position not walkable: " +
537 to_string(startPositionCandidate.getX()) +
", " +
538 to_string(startPositionCandidate.getY()) +
", " +
539 to_string(startPositionCandidate.getZ()) +
" / " +
540 to_string(startYHeight)
546 startPositionComputed = startPositionCandidate;
547 startPositionComputed.
setY(startYHeight);
552 for (
const auto& endPositionCandidate: endPositionCandidates) {
553 Vector3 endPositionComputed = endPositionCandidate;
554 float endYHeight = endPositionComputed.
getY();
555 if (alternativeEndSteps > 0 &&
557 endPositionComputed.
getX(),
558 endPositionComputed.
getY(),
559 endPositionComputed.
getZ(),
562 scaleActorBoundingVolumes,
568 "PathFinding::findPath(): End position not walkable: " +
569 to_string(endPositionComputed.
getX()) +
", " +
570 to_string(endPositionComputed.
getY()) +
", " +
571 to_string(endPositionComputed.
getZ()) +
" / " +
572 to_string(endYHeight)
578 endPositionComputed.
setY(endYHeight);
584 to_string(startPositionComputed.
getX()) +
", " +
585 to_string(startPositionComputed.
getY()) +
", " +
586 to_string(startPositionComputed.
getZ()) +
" --> " +
587 to_string(endPositionComputed.
getX()) +
", " +
588 to_string(endPositionComputed.
getY()) +
", " +
589 to_string(endPositionComputed.
getZ())
598 start->position = startPositionComputed;
599 start->costsAll = 0.0f;
600 start->costsReachPoint = 0.0f;
601 start->costsEstimated = 0.0f;
606 start->position.getX(),
607 start->position.getY(),
608 start->position.getZ(),
630 start->costsAll = start->costsEstimated;
638 for (
auto stepIdx = 0; done ==
false && stepIdx <
stepsMax; stepIdx++) {
648 for (
const auto& [openNodeId, openNode]:
openNodes) {
650 if (endNodeCandidate ==
nullptr || openNode->
costsAll < endNodeCandidate->
costsAll) endNodeCandidate = openNode;
654 if (endNodeCandidate ==
nullptr) {
660 if (endNode !=
nullptr) {
666 for (
auto pathNode = &
end; pathNode !=
nullptr; pathNode = (nodeIt = (pathNode->hasPreviousNode ==
false?
closedNodes.end():
closedNodes.find(pathNode->previousNodeId))) !=
closedNodes.end()?nodeIt->second:
nullptr) {
678 path.push_back(pathNode->position);
680 reverse(path.begin(), path.end());
681 if (path.size() > 1) path.erase(path.begin());
682 if (path.size() == 0) {
684 path.push_back(endPositionComputed);
690 const auto node = endNodeCandidate;
692 step(node,
stepSize, scaleActorBoundingVolumes,
nullptr,
false, customTest);
705 if (success ==
true || tries >= currentMaxTries + forcedAlternativeEndSteps)
break;
710 Console::println(
"PathFinding::findPath(): end position were not walkable!");
726 if (
VERBOSE ==
true && tries > 1)
Console::println(
"PathFinding::findPath(): time: " + to_string(
Time::getCurrentMillis() - now) +
"ms / " + to_string(tries) +
" tries, success = " + to_string(success) +
", path steps: " + to_string(path.size()));
729 if (customTest !=
nullptr) customTest->
dispose();
737 if (path.empty() ==
true) {
743 if (customTest !=
nullptr) customTest->
initialize();
749 auto actorBoundingVolume = make_unique<OrientedBoundingBox>(
751 OrientedBoundingBox::AABB_AXIS_X,
752 OrientedBoundingBox::AABB_AXIS_Y,
753 OrientedBoundingBox::AABB_AXIS_Z,
760 world->
addDynamicCollisionBody(
"tdme.pathfinding.actor", Body::COLLISION_TYPEID_RESERVED,
true, actorTransform, { actorBoundingVolume.get() });
763 auto actorBoundingVolumeSlopeTest = make_unique<OrientedBoundingBox>(
765 OrientedBoundingBox::AABB_AXIS_X,
766 OrientedBoundingBox::AABB_AXIS_Y,
767 OrientedBoundingBox::AABB_AXIS_Z,
770 world->
addDynamicCollisionBody(
"tdme.pathfinding.actor.slopetest", Body::COLLISION_TYPEID_RESERVED,
true, actorTransform, { actorBoundingVolumeSlopeTest.get() });
773 auto zMin =
static_cast<int>(Math::ceil(-depth / 2.0f /
flowMapStepSize));
774 auto zMax =
static_cast<int>(Math::ceil(depth / 2.0f /
flowMapStepSize));
775 auto xMin =
static_cast<int>(Math::ceil(-width / 2.0f /
flowMapStepSize));
776 auto xMax =
static_cast<int>(Math::ceil(width / 2.0f /
flowMapStepSize));
777 const vector<Vector3> emptyPath = { center };
778 const vector<Vector3>& pathToUse = path.empty() ==
false?path:emptyPath;
781 if (endPositions.size() == 0) {
801 for (
const auto& endPosition: endPositions) {
811 node->position.set(nodePosition).setY(nodeYHeight);
812 node->costsReachPoint = 0.0f;
816 node->id =
toIdInt(node->x, node->y, node->z);
819 node->costsAll = node->costsEstimated;
826 for (
const auto& _centerPathNode: pathToUse) {
829 _centerPathNode.getY(),
834 for (
auto z = zMin; z <= zMax; z++) {
835 for (
auto x = xMin; x <= xMax; x++) {
841 nodesToTest.insert(nodeId);
850 for (
const auto& [openNodeCandidateId, openNodeCandidate]:
openNodes) {
851 if (openNode ==
nullptr || openNodeCandidate->
costsAll < openNode->
costsAll) openNode = openNodeCandidate;
853 if (openNode ==
nullptr)
break;
865 flowMap->acquireReference();
866 for (
const auto& _centerPathNode: pathToUse) {
869 _centerPathNode.getY(),
874 for (
auto z = zMin; z <= zMax; z++) {
875 for (
auto x = xMin; x <= xMax; x++) {
892 if (flowMap->hasCell(cellId) ==
true)
continue;
899 auto node = nodeIt->second;
901 cellPosition.setY(node->position.getY());
906 for (
auto _z = -1; _z <= 1; _z++)
907 for (
auto _x = -1; _x <= 1; _x++)
908 if (_z != 0 || _x != 0) {
910 auto neighbourNodeId =
toIdInt(
911 centerPathNodeX + x + _x,
913 centerPathNodeZ + z + _z
916 if (neighbourNodeId == nodeId)
continue;
918 auto neighbourNodeIt =
closedNodes.find(neighbourNodeId);
924 const auto& neighbourNode = neighbourNodeIt->second;
925 if (minCostsNode ==
nullptr || neighbourNode->
costsReachPoint < minCosts) {
926 minCostsNode = neighbourNode;
931 if (minCostsNode !=
nullptr) {
938 to_string(node->position.getX()) +
", " +
939 to_string(node->position.getY()) +
", " +
940 to_string(node->position.getZ()) +
": " +
941 to_string(minCostsNode == node) +
"; " +
942 to_string(cellPosition.getX()) +
", " +
943 to_string(cellPosition.getY()) +
", " +
944 to_string(cellPosition.getZ())
965 for (
const auto& _centerPathNode: pathToUse) {
968 _centerPathNode.getY(),
973 for (
auto z = zMin; z <= zMax; z++) {
974 for (
auto x = xMin; x <= xMax; x++) {
984 auto cell = flowMap->getCell(cellId);
985 if (cell ==
nullptr)
continue;
986 auto topCell = flowMap->getCell(
FlowMap::toIdInt(centerPathNodeX + x, centerPathNodeZ + z - 1));
987 if (topCell ==
nullptr && Math::abs(cell->getDirection().getX()) > 0.0f && cell->getDirection().getZ() < 0.0f){
988 cell->setDirection(cell->getDirection().clone().setZ(0.0f).normalize());
990 auto bottomCell = flowMap->getCell(
FlowMap::toIdInt(centerPathNodeX + x, centerPathNodeZ + z + 1));
991 if (bottomCell ==
nullptr && Math::abs(cell->getDirection().getX()) > 0.0f && cell->getDirection().getZ() > 0.0f){
992 cell->setDirection(cell->getDirection().clone().setZ(0.0f).normalize());
994 auto leftCell = flowMap->getCell(
FlowMap::toIdInt(centerPathNodeX + x - 1, centerPathNodeZ + z));
995 if (leftCell ==
nullptr && cell->getDirection().getX() < 0.0f && Math::abs(cell->getDirection().getZ()) > 0.0f){
996 cell->setDirection(cell->getDirection().clone().setX(0.0f).normalize());
998 auto rightCell = flowMap->getCell(
FlowMap::toIdInt(centerPathNodeX + x + 1, centerPathNodeZ + z));
999 if (rightCell ==
nullptr && cell->getDirection().getX() > 0.0f && Math::abs(cell->getDirection().getZ()) > 0.0f){
1000 cell->setDirection(cell->getDirection().clone().setX(0.0f).normalize());
1007 Vector3 lastCenterPathNode = pathToUse.size() < 2?
Vector3():pathToUse[0] - (pathToUse[1] - pathToUse[0]);
1008 unordered_set<string> cellsProcessed;
1009 for (
int i = pathToUse.size() - 1; i >= 0; i--) {
1010 auto _centerPathNode = pathToUse[i];
1011 auto centerPathNode =
Vector3(
1013 _centerPathNode.getY(),
1016 auto pathDirection = (lastCenterPathNode - centerPathNode).setY(0.0f).normalize();
1019 for (
auto z = zMin; z <= zMax; z++) {
1020 for (
auto x = xMin; x <= xMax; x++) {
1022 centerPathNodeX + x,
1025 auto cell = flowMap->getCell(cellId);
1026 if (cell ==
nullptr)
continue;
1029 auto hadMissingNeighborCell =
false;
1030 for (
auto nZ = -1; nZ < 2 && hadMissingNeighborCell ==
false; nZ++) {
1031 for (
auto nX = -1; nX < 2 && hadMissingNeighborCell ==
false; nX++) {
1032 if (nZ == 0 && nX == 0)
continue;
1034 centerPathNodeX + x + nX,
1035 centerPathNodeZ + z + nZ
1037 auto neighbourCell = flowMap->getCell(neighbourCellId);
1038 if (neighbourCell ==
nullptr) {
1039 cell->setMissingNeighborCell(
true);
1040 hadMissingNeighborCell =
true;
1049 auto pathNodeIdx = -1;
1051 for (
const auto& pathNode: pathToUse) {
1052 auto pathNodeCellAxis = pathNode - cell->getPosition();
1053 auto pathNodeCandidateDistanceSquared = pathNodeCellAxis.computeLengthSquared();
1054 if (pathNodeIdx == -1 || pathNodeCandidateDistanceSquared < pathNodeNodeDistanceSquared) {
1056 pathNodeNodeDistanceSquared = pathNodeCandidateDistanceSquared;
1060 cell->setPathNodeIdx(pathNodeIdx < pathToUse.size() - 1?pathNodeIdx + 1:pathNodeIdx);
1064 lastCenterPathNode = centerPathNode;
1072 if (customTest !=
nullptr) customTest->
dispose();
1079 vector<Vector3> path;
1086 path.push_back(current.
add(
step));
1088 path.push_back(
end);
ByteBuffer * getTextureData()
uint16_t getTextureWidth() const
void setTransform(const Transform &transform)
Set transform.
Dynamic physics world class.
bool doesCollideWith(uint16_t collisionTypeIds, Body *body, vector< Body * > &collisionBodies)
Check if world collides with given body.
void removeBody(const string &id)
Removes body identified by id.
Body * getBody(const string &id)
Returns body identified by id.
Body * determineHeight(uint16_t collisionTypeIds, float stepUpMax, const Vector3 &point, Vector3 &heightPoint, float minHeight=-10000.0f, float maxHeight=10000.0f)
Determine height on x,y,u while respecting step up max.
Body * addDynamicCollisionBody(const string &id, uint16_t collisionTypeId, bool enabled, const Transform &transform, const vector< BoundingVolume * > &boundingVolumes, bool hierarchy=false)
Add a dynamic collision body.
Bounding volume interface.
Oriented bounding box physics primitive.
Vector3 class representing vector3 mathematical structure and operations with x, y,...
float computeLength() const
Vector3 & add(float scalar)
Adds a scalar.
Vector3 & setY(float y)
Sets y component.
float computeLengthSquared() const
Vector3 clone() const
Clones this vector3.
Vector3 & sub(float scalar)
Subtracts a scalar.
Vector3 & set(float x, float y, float z)
Sets this vector3 by its components.
Vector3 & normalize()
Normalizes this vector3.
uint8_t get(int64_t position) const
static void println()
Print new line to console.
static constexpr float MAX_VALUE
static bool isNaN(float value)
Check if float is not a number.
int getIntegerPositionComponent(float value) const
Returns integer position component.
static const tuple< int, int > toIdInt(int x, int z)
Return string representation of given x,z integer flow map position representation for flow map cell ...
static float alignPositionComponent(float value, float stepSize)
Align position component.
unordered_map< tuple< uint8_t, uint8_t, int, int, int, uint16_t, bool >, float, WalkableCache_Hash > walkableCache
PathFindingNodesPool pathFindingNodesPool
unordered_map< tuple< int, int, int >, PathFindingNode *, PathFindingNodeId_Hash > closedNodes
const vector< Vector3 > generateDirectPath(const Vector3 &start, const Vector3 &end)
Generate direct path from start to end.
FlowMap * createFlowMap(const vector< Vector3 > &endPositions, const Vector3 ¢er, float depth, float width, const uint16_t collisionTypeIds, const vector< Vector3 > &path=vector< Vector3 >(), bool complete=true, PathFindingCustomTest *customTest=nullptr)
Create flow map.
bool isWalkable(float x, float y, float z, float &height, float stepSize, float scaleActorBoundingVolumes, bool flowMapRequest, uint16_t collisionTypeIds=0, bool ignoreStepUpMax=false)
Checks if a cell is walkable.
bool equalsLastNode(const PathFindingNode *a, const PathFindingNode *b)
Returns if nodes are equals for (last node test)
uint16_t skipOnCollisionTypeIds
static const tuple< int, int, int > toIdInt(int x, int y, int z)
Return string representation of given x,z integer flow map position representation for path finding i...
bool isSlopeWalkableInternal(float x, float y, float z, float successorX, float successorY, float successorZ, float stepSize, float scaleActorBoundingVolumes, bool flowMapRequest, PathFindingCustomTest *customTest=nullptr, uint16_t collisionTypeIds=0)
Checks if a cell is slope walkable.
float computeDistance(const PathFindingNode *a, const PathFindingNode *b)
Computes non square rooted distance between a and b.
float computeDistanceToEnd(const PathFindingNode *node)
Computes minimal non square rooted distance between node and end point.
~PathFinding()
Destructor.
bool equals(const PathFindingNode *a, float bX, float bY, float bZ)
Returns if nodes are equals.
uint16_t collisionTypeIds
static constexpr bool VERBOSE
static int getIntegerPositionComponent(float value, float stepSize)
Returns integer position component.
bool findPathCustom(const Vector3 &startPosition, const Vector3 &endPosition, float stepSize, float scaleActorBoundingVolumes, const uint16_t collisionTypeIds, vector< Vector3 > &path, int alternativeEndSteps=0, int maxTriesOverride=-1, PathFindingCustomTest *customTest=nullptr)
Finds path to given end position.
float flowMapScaleActorBoundingVolumes
const tuple< int, int, int > toId(float x, float y, float z)
Return path finding node id of given x, y, z position components.
bool isWalkableInternal(float x, float y, float z, float &height, float stepSize, float scaleActorBoundingVolumes, bool flowMapRequest, PathFindingCustomTest *customTest=nullptr, uint16_t collisionTypeIds=0, bool ignoreStepUpMax=false)
Checks if a cell is walkable.
unordered_map< tuple< int, int, int >, PathFindingNode *, PathFindingNodeId_Hash > openNodes
void step(PathFindingNode *node, float stepSize, float scaleActorBoundingVolumes, const unordered_set< tuple< int, int, int >, PathFindingNodeId_Hash > *nodesToTest, bool flowMapRequest, PathFindingCustomTest *customTest=nullptr)
Processes one step in AStar path finding.
void release(T *element)
Release element in pool for being reused.
T * allocate()
Allocate a new element from pool.
void reset()
Reset this pool.
virtual void releaseReference()
Releases a reference, thus decrementing the counter and delete it if reference counter is zero.
static constexpr float STEP_SIZE
static int64_t getCurrentMillis()
Retrieve current time in milliseconds.
Path finding custom test interface.
virtual void initialize()=0
Initialize custom test for a sequence of isWalkable calls for the current path finding execution.
virtual void dispose()=0
Disposes custom test after a sequence of isWalkable calls for the last path finding execution.
virtual bool isWalkable(PathFinding *pathFinding, float x, float y, float z)=0
Is walkable user test.
int y
Integer position along y axis.
int z
Integer position along z axis.
bool hasPreviousNode
Has previous node.
tuple< int, int, int > id
Node id.
int x
Integer position along x axis.
tuple< int, int, int > previousNodeId
Previous node.
float costsAll
Estimated costs to the end plus calculated costs from start to this node.
float costsEstimated
Estimated costs to get to the end.
float costsReachPoint
Calculated costs up to this point (from all previous nodes up to this node) to get to this coordinate...
Vector3 position
Position.