- Home /
Pathfinding help
I've created a fairly simple A* Pathfinding script, but I have encountered one problem. The pathfinder will try and take the shortest path, only to find that there's a one node gap between it and the target node and it keeps doubling back on itself. So it'll move up right next to the target node, but all the nodes leading around the pathfinder are all blocked (including the one in-between the pathfinder and the target node) and the only way out is the way it came. But as soon as it moves back the way it came, it tries to re-do what it just did, and then creates this loop where it just moves back & forth. I have no idea how to avoid this. What should I do?
Here's some of the code if it'll help you understand:
void CheckNode () {
float lowestF = Mathf.Infinity;
Transform nextNode = null;
int a = 0;
while(a < open.Count){
List<Transform> thisOpen = FindAdjacentNodes(open[a]);
bool addWeight = false;
float weight = 0;
foreach(Transform n in thisOpen){
if(!open.Contains(n) && !addWeight){
addWeight = false;
weight = 0;
}else{
addWeight = true;
weight = errorWeight;
}
}
if((((current.position - open[a].position).magnitude + (finish.position - open[a].position).magnitude) + weight) < lowestF){
nextNode = open[a];
lowestF = (current.position - open[a].position).magnitude + (finish.position - open[a].position).magnitude;
}
a++;
}
if(!closed.Contains(current)){
closed.Add(current);
}
current = nextNode;
if(!closed.Contains(current)){
closed.Add(current);
}
lastOpen = open;
open = FindAdjacentNodes(current);
if(current){
int b = 0;
while(b < nodes.Count){
int c = 0;
while(c < nodes[b].nodeVectors.Count){
foreach(Transform n in lastOpen){
if(n == nodes[b].nodeVectors[c]){
nodes[b].nodeVectors.Remove(nodes[b].nodeVectors[c]);
}
}
c++;
}
b++;
}
closed.Clear();
open.Clear();
closed.Add(start);
current = start;
}
current.renderer.material = green;
}
EDIT
So the above problem has been solved, but the pathfinding itself still gives me a weird path. I started this thread here if maybe you could help me out.
Answer by FlowStateGames · Dec 11, 2012 at 02:09 PM
First of all, I would encourage you to look into theta-star pathing, as it's not any more complicated than A*, is more efficient, etc. For your particular problem, it would be really nice to see more information, but I think I get the gist of the issue.
Okay, so basically you have two similar options for a solution to this:
Give your pathing system "lookahead" to pre-evaluate the next-node solution.
Give your system a "history" or move-buffer so that 'mistakes' won't be repeated.
From experience, I'd say that the first solution is preferable. There are two general ways to achieve this:
Naive lookahead: basically, your lookahead can only return a bool "pathNotValid". As you can guess, this will mean "if I move here, I'll have to move back". This is easy to evaluate, but relatively short on information.
Weighted lookahead: this method is a little more expensive, but returns much more information. Essentially, you buffer a full round of node evaluation for the prospective node you're going to move to. The only real difference is that you can apply some insane weight to the node you're currently on. This way, your algorithm can stay the same, because you'll be evaluating on weight; you're simply heavily-punishing backtracking.
To sum up, when you're evaluating the possible next nodes, queue them up with the most-desirable first, then do a lookahead to evaluate the next move from that node. Pass into this lookahead method the id of your current node, so that you can heavily weight backtracking.
EDIT: You are going to hate me for this, but I've done it before (not in Unity, sadly) and it is an amazing tool to have. What I would suggest is the following:
Tie the nodes to GameObjects which can be manually or procedurally placed in your scene.
Your goal is to be able to step through the pathfinding steps, and color the nodes each step to reflect their state in the algorithm (neighbor, current node, etc). This way you can create different scenarios in which to test your algorithm.
The more robust solution would be to indicate path weight visually. The two ways to do this would be to either float text above each node, or to use the color value of the material to denote weight (start at 255,255,255 then make the material darker and darker if it's a heavy path).
It's 3am, I hope this makes sense. If not, I'll rewrite in the morning.
So I tried the lookahead approach and wasn't able to get it to work. Basically what I did was check the node in front of it and check to see if there were any adjacent nodes besides the ones already on the open list. If there is, move on as normal, if not, I skipped that node. I tried doing that and I got weird effects; it started creating a weird path that ended up ter$$anonymous$$ating itself. I also tried just adding a weight to that node, and it moved in the right direction, but it ter$$anonymous$$ated too. Not sure if I understood you right.
This code adds the weight:
List thisOpen = FindAdjacentNodes(open[a]);
bool addWeight = false;
float weight = 0;
foreach(Transform n in thisOpen){
if(!open.Contains(n) && !addWeight){
addWeight = false;
weight = 0;
}else{
addWeight = true;
weight = errorWeight;
}
}
This code attempts to restart the search if original path doesn't work:
lastOpen = open;
open = FindAdjacentNodes(current);
if(open.Count < 1){
int b = 0;
while(b < nodes.Count){
int c = 0;
while(c < nodes[b].nodeVectors.Count){
foreach(Transform n in lastOpen){
if(n == nodes[b].nodeVectors[c]){
nodes[b].nodeVectors.Remove(nodes[b].nodeVectors[c]);
}
}
c++;
}
b++;
}
closed.Clear();
open.Clear();
closed.Add(start);
current = start;
open = FindAdjacentNodes(current);
}
Just a little bit more information if it'll help you understand.
Please see my edit above, let me know if it makes sense to you.
Yup, thats more or less what I've done, to check how its been going.
Your answer
Follow this Question
Related Questions
iTween, moving to a node on a path. 1 Answer
A* pathfinding, Re checking nodes 1 Answer
A* Pathfinding, destroying a path once it has reached its end 0 Answers
Aron Ganberg Astar - add nodes at runtime with pointgraph 0 Answers
Is it possible to store NavMeshAgents paths and assign them to other NavMeshAgents later? 1 Answer