Path Finding Resource Update: Dijkstra, A Star and Best First pathfinding solution
by Gabriel Notman · 04/03/2008 (10:29 am) · 62 comments
Here is an update on the resource:
garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=13326
It has been updated so that it easy easier to integrate and use with the likes of the fps starter kit.
Also a few bugs were found in the original resource which have been fixed here.
It does use the Script Array resource by Daniel Neilsen.
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=4711
However this has been included already.
To use this resource in new missions, simply walk around the mission and press the drop node key (bound to 'x' by default). This will drop a node at your player's current position and start building the navigation graph, adjacency data and cost information. You must then save the mission before exiting. This will save the nodes as part of the mission, and will also save out the path data to file in the missions directory with the same name as the mission but with the added extension of '.dat'.
Once you have a navigation graph with at least two nodes, you can see a visual representation in the world editor. Simply open the editor and select one of the nodes. This will show a blue line connecting each of the nodes which are adjacent, or connected.
A modified version of the stronghold mission has been included with this resource (including the path data).
It will show up as 'AI Stronghold' in your missions list.
Here is a screen shot showing the navigation graph:

The AiPlayer script has been modified so that it will follow a path using this resource (if the navigation graph is available). Kork will simply pick a random location (it uses one of the graph's nodes as a target position, but it could use any coordinates), find a path to that location, and then head on his way. When he arrives he will wait one second and then repeat this process. This is not the most intelligent of behaviour, but it is there to simply demonstrate the path finding.
If you have the world editor open and one of the nodes selected, you will see the most recent found path drawn in green instead of the standard blue.
Unfortunately the graph data pushes this resource over the size limit.
You can download the resource here:
www.gabriel-notman.com/upload/PathFinding.zip
Known issues (April 12th 08):
1. Inefficient search of the start and end nodes. Currently it searches all the nodes in the graph to find the nearest nodes to both start and end positions. It uses a raycast to determine if it that node is reachable from either location. Initial testing on a ~100 node graph indicated this was taking up 90-95% of the time costs of the pathfinding. This cost will also increase with larger graphs (included demo graph has ~500 nodes). A potential fix is to add a maximum radius when searching for the start and end nodes, so reducing and limiting the raycast costs.
2. Possible bug with very short paths. If the closest node to both the start and end locations is the same, it may be added to the list twice.
3. Possible problem with very long paths. The full path is returned as a space separated list of node IDs in a single string. This has the potential to exceed the maximum string length, although I'm not sure what the limit is.
4. Nearest node may cause backtracking. When searching for a new path, it is possible that the AIPlayer will have to turn around and walk a few steps backwards. This is because the nearest node may be behind him. A possible solution will be to add an angular limit on the nodes to search for, so that the path only looks to use nodes in front of the AIPlayer, as starting nodes for the potential path.
I hope to work out these issues and update the resource soon.
garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=13326
It has been updated so that it easy easier to integrate and use with the likes of the fps starter kit.
Also a few bugs were found in the original resource which have been fixed here.
It does use the Script Array resource by Daniel Neilsen.
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=4711
However this has been included already.
To use this resource in new missions, simply walk around the mission and press the drop node key (bound to 'x' by default). This will drop a node at your player's current position and start building the navigation graph, adjacency data and cost information. You must then save the mission before exiting. This will save the nodes as part of the mission, and will also save out the path data to file in the missions directory with the same name as the mission but with the added extension of '.dat'.
Once you have a navigation graph with at least two nodes, you can see a visual representation in the world editor. Simply open the editor and select one of the nodes. This will show a blue line connecting each of the nodes which are adjacent, or connected.
A modified version of the stronghold mission has been included with this resource (including the path data).
It will show up as 'AI Stronghold' in your missions list.
Here is a screen shot showing the navigation graph:

The AiPlayer script has been modified so that it will follow a path using this resource (if the navigation graph is available). Kork will simply pick a random location (it uses one of the graph's nodes as a target position, but it could use any coordinates), find a path to that location, and then head on his way. When he arrives he will wait one second and then repeat this process. This is not the most intelligent of behaviour, but it is there to simply demonstrate the path finding.
If you have the world editor open and one of the nodes selected, you will see the most recent found path drawn in green instead of the standard blue.
Unfortunately the graph data pushes this resource over the size limit.
You can download the resource here:
www.gabriel-notman.com/upload/PathFinding.zip
Known issues (April 12th 08):
1. Inefficient search of the start and end nodes. Currently it searches all the nodes in the graph to find the nearest nodes to both start and end positions. It uses a raycast to determine if it that node is reachable from either location. Initial testing on a ~100 node graph indicated this was taking up 90-95% of the time costs of the pathfinding. This cost will also increase with larger graphs (included demo graph has ~500 nodes). A potential fix is to add a maximum radius when searching for the start and end nodes, so reducing and limiting the raycast costs.
2. Possible bug with very short paths. If the closest node to both the start and end locations is the same, it may be added to the list twice.
3. Possible problem with very long paths. The full path is returned as a space separated list of node IDs in a single string. This has the potential to exceed the maximum string length, although I'm not sure what the limit is.
4. Nearest node may cause backtracking. When searching for a new path, it is possible that the AIPlayer will have to turn around and walk a few steps backwards. This is because the nearest node may be behind him. A possible solution will be to add an angular limit on the nodes to search for, so that the path only looks to use nodes in front of the AIPlayer, as starting nodes for the potential path.
I hope to work out these issues and update the resource soon.
About the author
#2
A basic mechanism has been included so that if it gets stuck (the bot hasn't moved at all since the last think cycle), it then searches for another path.
Gabriel
04/03/2008 (2:50 pm)
No the adjacency data is static (it takes quite a long time to process). However it wouldn't be difficult to do a raycast check to the next node, each time the bot reaches a node.A basic mechanism has been included so that if it gets stuck (the bot hasn't moved at all since the last think cycle), it then searches for another path.
Gabriel
#3
04/08/2008 (5:14 pm)
This is a great user-friendly update to a really good resource.
#4
04/22/2008 (5:05 am)
Has anyone gotten more then one Kork running on the same or different paths? If your willing to share some the code that would be great. If not ideas/pointers will also work.
#5
Currently it only spawns one bot (kork) and keeps track of that bot in a dynamic field called player (AIMangager.player), this dynamic field is created in AIManager::Think() by making a call to AIManager::Spawn. It is also used in that function to determine if Kork is still alive or whether to spawn him again. Additionally I have used that dynamic field to check if Kork gets stuck.
Gabriel
04/22/2008 (3:13 pm)
Try modifying the AIManager script class whose functions can be found at the base of AIPlayer.cs. Currently it only spawns one bot (kork) and keeps track of that bot in a dynamic field called player (AIMangager.player), this dynamic field is created in AIManager::Think() by making a call to AIManager::Spawn. It is also used in that function to determine if Kork is still alive or whether to spawn him again. Additionally I have used that dynamic field to check if Kork gets stuck.
Gabriel
#6
05/20/2008 (11:47 am)
I have a new request. I have more than 10 Korks running on the same path right now and would I would like to create multiple separate paths with Korks running on them. If anyone is willing to share some code to get this working that would be great. If not ideas or pointers will work.
#7
I got the following errors:
c:\torque\enginepathfindoct2008\engine\editor\worldeditor.cc(2530) : error C3861: 'renderAIPaths': identifier not found
c:\torque\enginepathfindoct2008\engine\editor\worldeditor.cc(2617) : error C2039: 'renderAIPaths' : is not a member of 'WorldEditor'
c:\torque\enginepathfindoct2008\engine\editor\worldeditor.h(21) : see declaration of 'WorldEditor'
c:\torque\enginepathfindoct2008\engine\editor\worldeditor.cc(2629) : error C3861: 'renderPathAdjs': identifier not found
c:\torque\enginepathfindoct2008\engine\editor\worldeditor.cc(2634) : error C2039: 'renderPathAdjs' : is not a member of 'WorldEditor'
c:\torque\enginepathfindoct2008\engine\editor\worldeditor.h(21) : see declaration of 'WorldEditor'
What could be causing these errors? I did add all the files to the project. And I followed all the instructions to the best of my knowledge, including all of the code changes to existing code. Still not working.
10/27/2008 (10:32 am)
I tried compiling this in VC++ 2008. I got the following errors:
c:\torque\enginepathfindoct2008\engine\editor\worldeditor.cc(2530) : error C3861: 'renderAIPaths': identifier not found
c:\torque\enginepathfindoct2008\engine\editor\worldeditor.cc(2617) : error C2039: 'renderAIPaths' : is not a member of 'WorldEditor'
c:\torque\enginepathfindoct2008\engine\editor\worldeditor.h(21) : see declaration of 'WorldEditor'
c:\torque\enginepathfindoct2008\engine\editor\worldeditor.cc(2629) : error C3861: 'renderPathAdjs': identifier not found
c:\torque\enginepathfindoct2008\engine\editor\worldeditor.cc(2634) : error C2039: 'renderPathAdjs' : is not a member of 'WorldEditor'
c:\torque\enginepathfindoct2008\engine\editor\worldeditor.h(21) : see declaration of 'WorldEditor'
What could be causing these errors? I did add all the files to the project. And I followed all the instructions to the best of my knowledge, including all of the code changes to existing code. Still not working.
#8
10/27/2008 (1:26 pm)
Please disregard my previous post. I had missed one of the header files (duh).
#9
10/27/2008 (2:08 pm)
Great resource. Works well in 1.5.2. Thanks for this. Very flexible and useful.
#10
10/28/2008 (8:20 am)
I am having a problem where when I try this with a new mission, and save that mission, a "dat" file is NOT created in the missions folder. How do I resolve this?
#11
The script changes in there are meant to save out the adjacency data when the mission is saved (using the mission's filename). It is possible that it isn't using the new filename. I will double check this.
Alternatively you saved the data manually by typing SavePaths() into the console.
Gabriel
10/28/2008 (8:33 am)
Have you made the changes to scripts/creator/editor/EditorGui.cs?The script changes in there are meant to save out the adjacency data when the mission is saved (using the mission's filename). It is possible that it isn't using the new filename. I will double check this.
Alternatively you saved the data manually by typing SavePaths() into the console.
Gabriel
#12
10/28/2008 (8:39 am)
OK I see, yes that was the problem.
#13
my server/scripts/aiPaths.cs function looks like this:
function SavePaths()
{
echo ("trying to save");
if (isObject(AiPaths))
AiPaths.saveAdjs("./" @ $Server::MissionFile @ ".dat");
}
And I am not seeing the words "trying to save" in my console.log, whether I type
SavePaths(); into the console
or
Whether I save the mission.
I did make the changes to the creator/editor files, etc. as noted.
I also cleaned out all of my .cs.dso files globally. I don't know why it won't save my stuff. It saves the nodes, obviously, but since the aiPaths.cs file is not active or working, then my paths are not being built between the nodes.
I did add
exec("./nodes.cs");
exec("./aiPaths.cs");
to my onServerCreated function in game.cs.
What could I be doing wrong now???
10/28/2008 (9:12 am)
Actually, no , it wasn't. my server/scripts/aiPaths.cs function looks like this:
function SavePaths()
{
echo ("trying to save");
if (isObject(AiPaths))
AiPaths.saveAdjs("./" @ $Server::MissionFile @ ".dat");
}
And I am not seeing the words "trying to save" in my console.log, whether I type
SavePaths(); into the console
or
Whether I save the mission.
I did make the changes to the creator/editor files, etc. as noted.
I also cleaned out all of my .cs.dso files globally. I don't know why it won't save my stuff. It saves the nodes, obviously, but since the aiPaths.cs file is not active or working, then my paths are not being built between the nodes.
I did add
exec("./nodes.cs");
exec("./aiPaths.cs");
to my onServerCreated function in game.cs.
What could I be doing wrong now???
#14
It is getting my save information but this is what is being spit out in the console:
==>SavePaths();
trying to save
AIPathGroup::SaveAdjs - Cannot write Adjs file without first generating Adjs --see createAdjs(...)/loadAdjs(...)
AIPathGroup::findPath -- Adjaceny matrix invalid --see createAdjs(...)
390.176 388.475 223.541
459.139 256.571 219.817
AIPathGroup::findPath -- Adjaceny matrix invalid --see createAdjs(...)
390.176 388.475 223.541
459.139 256.571 219.817
AIPathGroup::findPath -- Adjaceny matrix invalid --see createAdjs(...)
390.176 388.475 223.541
etc..............................
10/28/2008 (9:18 am)
Ok, new info.....It is getting my save information but this is what is being spit out in the console:
==>SavePaths();
trying to save
AIPathGroup::SaveAdjs - Cannot write Adjs file without first generating Adjs --see createAdjs(...)/loadAdjs(...)
AIPathGroup::findPath -- Adjaceny matrix invalid --see createAdjs(...)
390.176 388.475 223.541
459.139 256.571 219.817
AIPathGroup::findPath -- Adjaceny matrix invalid --see createAdjs(...)
390.176 388.475 223.541
459.139 256.571 219.817
AIPathGroup::findPath -- Adjaceny matrix invalid --see createAdjs(...)
390.176 388.475 223.541
etc..............................
#15
Make sure you have added at least two way point nodes then call AiPaths.createAdjs(...).
See the documentation for the parameters to pass to that function.
Gabriel
10/28/2008 (9:26 am)
Before you can save out the adjacency data you must first generate it.Make sure you have added at least two way point nodes then call AiPaths.createAdjs(...).
See the documentation for the parameters to pass to that function.
Gabriel
#16
createAdjs(type,)
This function takes one or two parameters and generates the adjacencies based on the type specified. Valid types are defined in the enumerator ADJTYPES. With the HEURISTIC type doing both a line of sight and a distance check (distance is specified in the second parameter).
I apologize for my lack of clarity on this. I still don't understand which parameter to pass to the function. Can you nudge me in the right direction?
In other words, I can simply do:
AiPaths.createAdjs(HEURISTIC , 40) and that should work?
It does not seem to be working properly. Does not seem to be generating the paths.
10/28/2008 (9:32 am)
Ok, thanks Gabriel... I see you havecreateAdjs(type,
This function takes one or two parameters and generates the adjacencies based on the type specified. Valid types are defined in the enumerator ADJTYPES. With the HEURISTIC type doing both a line of sight and a distance check (distance is specified in the second parameter).
I apologize for my lack of clarity on this. I still don't understand which parameter to pass to the function. Can you nudge me in the right direction?
In other words, I can simply do:
AiPaths.createAdjs(HEURISTIC , 40) and that should work?
It does not seem to be working properly. Does not seem to be generating the paths.
#17
check your gmail (the one on file for your gg account).
10/28/2008 (9:52 am)
I need to hire you for 1/2 hour or less. I just sent an email to your gmail. check your gmail (the one on file for your gg account).
#18
10/28/2008 (11:50 am)
Nevermind, I figured it out, it was just some batty code on my end which I fixed.
#19
10/28/2008 (11:51 am)
I cannot stress how useful this is. I was able to get pathfinding working so that the bot constantly finds the character, avoiding several complicated maze-like obstacles. This is an excellent and very valuable resource.
#20
Thanks in advance
03/16/2009 (3:21 am)
i cannot find dgl/dgl.h file in the resources given by and also in engine to i am using tgea 1.8.0 version for windows.Help me to fix this.Thanks in advance

Torque Owner Cinder Games