Skip to content

Commit acb6059

Browse files
authored
Merge pull request #70 from cortex-command-community/pathfinding-tweaks
Pathfinding Fix
2 parents d81e510 + 5b4370b commit acb6059

File tree

2 files changed

+34
-15
lines changed

2 files changed

+34
-15
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
1818

1919
<details><summary><b>Fixed</b></summary>
2020

21+
- Reverted a change to pathfinding, that although was technically accurate, caused issues with the AI being too eager to path up-and-over obstacles instead of through them. In the future this will likely be revisited when we get jump-aware pathfinding.
22+
2123
</details>
2224

2325
<details><summary><b>Removed</b></summary>

Source/System/PathFinder.cpp

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -210,24 +210,25 @@ std::shared_ptr<volatile PathRequest> PathFinder::CalculatePathAsync(Vector star
210210
const_cast<Vector&>(pathRequest->startPos) = start;
211211
const_cast<Vector&>(pathRequest->targetPos) = end;
212212

213-
g_ThreadMan.GetBackgroundThreadPool().push_task([this, start, end, digStrength, callback](std::shared_ptr<volatile PathRequest> volRequest) {
214-
// Cast away the volatile-ness - only matters outside (and complicates the API otherwise)
215-
PathRequest& request = const_cast<PathRequest&>(*volRequest);
213+
g_ThreadMan.GetBackgroundThreadPool().push_task(
214+
[this, start, end, digStrength, callback](std::shared_ptr<volatile PathRequest> volRequest) {
215+
// Cast away the volatile-ness - only matters outside (and complicates the API otherwise)
216+
PathRequest& request = const_cast<PathRequest&>(*volRequest);
216217

217-
int status = this->CalculatePath(start, end, request.path, request.totalCost, digStrength);
218+
int status = this->CalculatePath(start, end, request.path, request.totalCost, digStrength);
218219

219-
request.status = status;
220-
request.pathLength = request.path.size();
220+
request.status = status;
221+
request.pathLength = request.path.size();
221222

222-
if (callback) {
223-
callback(volRequest);
224-
}
223+
if (callback) {
224+
callback(volRequest);
225+
}
225226

226-
// Have to set to complete after the callback, so anything that blocks on it knows that the callback will have been called by now
227-
// This has the awkward side-effect that the complete flag is actually false during the callback - but that's fine, if it's called we know it's complete anyways
228-
request.complete = true;
229-
},
230-
pathRequest);
227+
// Have to set to complete after the callback, so anything that blocks on it knows that the callback will have been called by now
228+
// This has the awkward side-effect that the complete flag is actually false during the callback - but that's fine, if it's called we know it's complete anyways
229+
request.complete = true;
230+
},
231+
pathRequest);
231232

232233
return pathRequest;
233234
}
@@ -279,7 +280,11 @@ std::vector<int> PathFinder::RecalculateAreaCosts(std::deque<Box>& boxList, int
279280
}
280281

281282
float PathFinder::LeastCostEstimate(void* startState, void* endState) {
282-
return g_SceneMan.ShortestDistance((static_cast<PathNode*>(startState))->Pos, (static_cast<PathNode*>(endState))->Pos).GetMagnitude() / m_NodeDimension;
283+
// Now, it's technically correct to divide this by NodeDimension in order to not get an extreme overestimate of cost (by a factor of 20!)
284+
// But... turns out doing so actually makes pathfinding worse, because it encourages taking the cheapest path up and around obstable instead of straight through them
285+
// This is a combination of no jump-aware pathing and material transition cost balancing
286+
// TODO: When the time comes, fix this (again) ;)
287+
return g_SceneMan.ShortestDistance((static_cast<PathNode*>(startState))->Pos, (static_cast<PathNode*>(endState))->Pos).GetMagnitude() /* / m_NodeDimension*/;
283288
}
284289

285290
void PathFinder::AdjacentCost(void* state, std::vector<micropather::StateCost>* adjacentList) {
@@ -300,16 +305,19 @@ void PathFinder::AdjacentCost(void* state, std::vector<micropather::StateCost>*
300305
adjCost.state = static_cast<void*>(node->Up);
301306
adjacentList->push_back(adjCost);
302307
}
308+
303309
if (node->Right && node->Right->m_Navigatable) {
304310
adjCost.cost = 1.0F + GetMaterialTransitionCost(*node->RightMaterial) + radiatedCost;
305311
adjCost.state = static_cast<void*>(node->Right);
306312
adjacentList->push_back(adjCost);
307313
}
314+
308315
if (node->Down && node->Down->m_Navigatable) {
309316
adjCost.cost = 1.0F + GetMaterialTransitionCost(*node->DownMaterial) + radiatedCost;
310317
adjCost.state = static_cast<void*>(node->Down);
311318
adjacentList->push_back(adjCost);
312319
}
320+
313321
if (node->Left && node->Left->m_Navigatable) {
314322
adjCost.cost = 1.0F + GetMaterialTransitionCost(*node->LeftMaterial) + radiatedCost;
315323
adjCost.state = static_cast<void*>(node->Left);
@@ -322,16 +330,19 @@ void PathFinder::AdjacentCost(void* state, std::vector<micropather::StateCost>*
322330
adjCost.state = static_cast<void*>(node->UpRight);
323331
adjacentList->push_back(adjCost);
324332
}
333+
325334
if (node->RightDown && node->RightDown->m_Navigatable) {
326335
adjCost.cost = 1.4F + (GetMaterialTransitionCost(*node->RightDownMaterial) * 1.4F) + radiatedCost;
327336
adjCost.state = static_cast<void*>(node->RightDown);
328337
adjacentList->push_back(adjCost);
329338
}
339+
330340
if (node->DownLeft && node->DownLeft->m_Navigatable) {
331341
adjCost.cost = 1.4F + (GetMaterialTransitionCost(*node->DownLeftMaterial) * 1.4F) + radiatedCost;
332342
adjCost.state = static_cast<void*>(node->DownLeft);
333343
adjacentList->push_back(adjCost);
334344
}
345+
335346
if (node->LeftUp && node->LeftUp->m_Navigatable) {
336347
adjCost.cost = 1.4F + extraUpCost + (GetMaterialTransitionCost(*node->LeftUpMaterial) * 1.4F * 3.0F) + radiatedCost; // Three times more expensive when digging.
337348
adjCost.state = static_cast<void*>(node->LeftUp);
@@ -349,10 +360,12 @@ bool PathFinder::PositionsAreTheSamePathNode(const Vector& pos1, const Vector& p
349360

350361
float PathFinder::GetMaterialTransitionCost(const Material& material) const {
351362
float strength = material.GetIntegrity();
363+
352364
// Always treat doors as diggable.
353365
if (strength > s_DigStrength && material.GetIndex() != MaterialColorKeys::g_MaterialDoor) {
354366
strength *= 1000.0F;
355367
}
368+
356369
return strength;
357370
}
358371

@@ -377,14 +390,17 @@ bool PathFinder::UpdateNodeCosts(PathNode* node) const {
377390
Vector offset(0.0F, 3.0F);
378391
node->RightMaterial = getStrongerMaterial(StrongestMaterialAlongLine(node->Pos - offset, node->Right->Pos - offset), StrongestMaterialAlongLine(node->Pos + offset, node->Right->Pos + offset));
379392
}
393+
380394
if (node->Down) {
381395
Vector offset(3.0F, 0.0F);
382396
node->DownMaterial = getStrongerMaterial(StrongestMaterialAlongLine(node->Pos - offset, node->Down->Pos - offset), StrongestMaterialAlongLine(node->Pos + offset, node->Down->Pos + offset));
383397
}
398+
384399
if (node->UpRight) {
385400
Vector offset(2.0F, 2.0F);
386401
node->UpRightMaterial = getStrongerMaterial(StrongestMaterialAlongLine(node->Pos - offset, node->UpRight->Pos - offset), StrongestMaterialAlongLine(node->Pos + offset, node->UpRight->Pos + offset));
387402
}
403+
388404
if (node->RightDown) {
389405
Vector offset(2.0F, -2.0F);
390406
node->RightDownMaterial = getStrongerMaterial(StrongestMaterialAlongLine(node->Pos - offset, node->RightDown->Pos - offset), StrongestMaterialAlongLine(node->Pos + offset, node->RightDown->Pos + offset));
@@ -442,6 +458,7 @@ float PathFinder::GetNodeAverageTransitionCost(const PathNode& node) const {
442458
count++;
443459
}
444460
}
461+
445462
return totalCostOfAdjacentNodes / std::max(static_cast<float>(count), 1.0F);
446463
}
447464

0 commit comments

Comments
 (0)