Game Development Community

dev|Pro Game Development Curriculum

Flexible A* Pathfinding System

by Dan Keller · 04/08/2008 (2:15 pm) · 203 comments

1.8.1 version here!

Download

Note: The TGEA version in the download is newer than the TGE version. Most people are using TGEA now, anyways. If you want the newer version in TGE, you can port it yourself, it shouldn't be too bad. If there is some interest in it and someone does a port, just send it to me and I'll put it up here.

Installation - TGEA

Add aStar.h, aStar.cpp, aStarIO.cpp, and aStarMesh.cpp to your project (in T3D). Replace or merge aiPlayer.cpp and .h with the files in in the zip.

Add #include "T3D/aStar.h" on top of sceneState.cpp

Add the commented part in SceneState::renderCurrentImages():
PROFILE_START(RenderInstManagerRender);
   gRenderInstManager.render();
   PROFILE_END();
//aStar
#ifdef AI_RENDER
   AStar::Get()->render(this);
#endif
//aStar
   gRenderInstManager.clear();

   mInteriorList.clear();


Add this in game/tools/missionEditor/scripts/editors/creator.ed.cs line 146:
%Mission_Item[6] = "NavMesh";

Add the following function at the end of game/tools/missionEditor/gui/objectBuilderGui.ed.gui:
function ObjectBuilderGui::buildNavMesh(%this)
{
	%this.className = "NavMesh";
	%this.process();
}

In [game]/scriptsAndAssets/server/scripts/game.cs, at the end of startGame(), add
readPaths();

At the end of endGame(), add
deletePaths();

before resetMission();

For an example, add aiDemo.mis.


Installation - TGE

Add the aStar.cc and aStar.h files to your project. Replace or merge aiPlayer.cc and .h with the files in in the zip.

In sceneState.cc, after the includes, add
#include "game/aStar.h"

in renderCurrentImages(), around line 481, add the commented code
for (i = 0; i < mTranslucentEndImages.size(); i++)
      renderImage(this, mTranslucentEndImages[i]);
//aStar
#ifdef AI_RENDER
   gAStar.render(this);
#endif
//aStar
   glMatrixMode(GL_MODELVIEW);
   glPopMatrix();

Save and compile.

In creator/editor/EditorGui.cs, at line 1306, change
%Mission_Item[3] = "Trigger";
   %Mission_Item[4] = "PhysicalZone";
   %Mission_Item[5] = "Camera";

to

%Mission_Item[3] = "NavMesh";
   %Mission_Item[4] = "Trigger";
   %Mission_Item[5] = "PhysicalZone";
   %Mission_Item[6] = "Camera";

In creator/editor/objectBuilderGui.gui, at line 643, add
function ObjectBuilderGui::buildNavMesh(%this)
{
	%this.className = "NavMesh";
	%this.process();
}

In [game]/server/scripts/game.cs, at the end of startGame(), add
readPaths();

At the end of endGame(), add
deletePaths();

before resetMission();

For an example, add aiDemo.mis.

Use

To add navigation points, open the mission editor creator. NavMesh objects are under Mission Objects / Mission. The properties are:
Interval - distance between points
XSize - number of points in x direction
YSize - number of points in y direction
Height - how far up or down the object will look to place points

There are two global preferences you can change. One is $Pref::AStar::Render. It controls whether or not the navigation mesh is rendered. Turn it on when editing the mesh, turn it off otherwise. The other is $Pref::AStar::Clearence. This controls the minimum horizontal clearance between two nodes when building paths. If you change this after creating points, you need to call buildPaths for it to effect those points.

There are three functions for path caching. Do not call any of these while the mission editor is running, it may get all messed up. They are
- deletePaths Deletes all NavMesh objects and all nodes.
- writePaths Writes all nodes to a file (called [mission name].as) that is loaded automatically on mission startup. This is the only function you need to call manually; call it once you're done editing the nav mesh.
- readPaths Reads nodes from file. Returns true on success, false on faliure.

Also there is
- buildPaths Manually rebuilds navigation information, for example if an object has been moved in the way of some nodes.

There is also a compiler switch, AI_RENDER, at the top of aStar.h. Comment this out when you distribute the game to remove all the nav mesh rendering code.

There are five functions that can be called on the AIPlayer object. They will return 0 on success, -1 on failure, and 1 if the bot is already where you want it to go. They are
- findPathTo This takes either a point or an object as an argument, and simply finds a way to the point.
- findCoverFrom This also takes a point or object, and finds a place hidden from it.
- searchCover This takes no arguments, and makes the bot go to the nearest place it can't see.
- sneakUpOn This takes either a point and a vector or an object as an argument. It finds a path to the point or the object that can't be seen by it.
- wander This takes a distance as an argument and wanders around for this distance.
#161
11/14/2009 (3:05 pm)
I used this method to spawn bots, but how you do it depends on what you're using it for.
#162
11/15/2009 (3:48 pm)
This is a fantastic resource. I was wondering - how hard would it be to allow a new obstacle to be inserted into the mesh and to have only the part of the mesh around that obstacle regenerated?
#163
11/15/2009 (3:58 pm)
It wouldn't be too hard- basically you'd want another version of the linkMeshes function in aStar.cpp with a bit of code after
for (cur = list; cur; cur = cur->next)
    {
that's something like
if ((cur->pos - editPt).len() > editDst)
        continue;
where editPt is where the obstacle is and editDst is how big it is.

Then you'll want to create another version of the buildPaths ConsoleFunction that takes editPt and editDst as arguments.
#164
11/17/2009 (7:47 am)
Has anyone gotten the default torque vehicles to use this method of path finding? I tried dropping the Boom Bot into the starter buggy and he just drove off to little clearing and started driving around in circles.

Also whats the best strategy for really huge terrains and this resource. I have 2 problems. buildPaths take a really long time when i cover the whole map with one grid and the rendering of the lines kills my pc('s performance).
#165
11/17/2009 (12:57 pm)
Hi Adam, the T3D resource download link is no longer working. Can you fix?
#166
11/19/2009 (3:32 pm)
If you have the new version, use the code
AStar::Get()->render(this);
But i can't guarantee that render() itself will work, because I don't have T3D.
#167
11/24/2009 (10:19 am)
hi dan
i try 1.8.1 version but compile have a error about
"fatal error C1083: Cannot open include file: 'T3D/aiManager.h': No such file or directory"

i check astar.h have change #include "T3D/aiManager.h"
so i search my TGEA_1_8_1 folder but cant see "aiManager.h" the file...
how am i get the aiManager.h file??

thx a lot ur help~
#168
11/24/2009 (10:33 am)
Quote:how am i get the aiManager.h file??

You'd need to get a license for the source code, which would provide the file, since you don't seem to have one.
#169
11/24/2009 (5:07 pm)
Whoops, just comment out the #include for that, it wasn't supposed to be there.
#170
11/30/2009 (12:54 am)
Awesome resource! Much better than the hapless wander functions I had scripted :)

Also, if anyone is interested, I have the following script used for NPCs to wander from one building to another. The buildings are, in this case, grouped into a Simset named Tents, and I just pick one at random and the NPC walks to it. Figure it's probably nice for a market scene (which is what I'm using it for):

function AIPlayer::bldgWander(%this)
{
   //Select a building and get its position
   %i = randInRange(0, Tents.getCount()-1); //Replace this with a rand function of your choice...
   %pos = Tents.getObject(%i).getPosition();
   %this.setAimLocation(%pos);
   %this.findPathTo(%pos);
}
#171
12/18/2009 (1:13 pm)
I'm using 1.8.1 and tne original resource is missing half of its own code, if anybody has a version that drops right into 1.8.1 can you post the files somewhere because the original resource download doesnt.

I had to copy the disStr function from the TGE version of the code and add the filestream header to even get it to compile.

In game it crashes without warning when trying to use wander, and when i try to enable the rendering i get all kinds of errors and warnings when compiling.

so again, if anybody has a version that works in stock 1.8.1 could you please post it?
#172
01/08/2010 (8:32 pm)
Implemented this into our T3D build after a bit of changes here and there it seems to be working without issue. I do have a question about 1 segment of code though in aStarMesh.cpp

sortPoints(pt);

   for (int i=0; i<sortVec.size(); i++)
      if (disSqr(sortVec[i]->loc, pt) > LOOK_DIS_SQR && !gServerContainer.castRay(sortVec[i]->loc, pt, ( InteriorObjectType | StaticTSObjectType | StaticShapeObjectType  ), &rInfo))
         return sortVec[i];

Any clue when that part in findPoint would actually be used to find a point that isn't matched in the first loop. I want to use this code in conjuction with our old path finding code since it is a bit more stupid and better suited for an MMO when there is no path finding needed (point A marker is clear to point B maker). If you try to plot a point that isn't in the mesh that 2nd bit of code really kills you. I took it out and haven't seen a lot of problems yet.
#173
01/08/2010 (9:12 pm)
The purpose of this code is to find reachable points farther away than sqrt(LOOK_DIS_SQR), if there are no reachable points closer. It won't hurt to comment it out, because it will just reject points too far away from a mesh. It was intended as a last resort to find a point before just giving up.
#174
01/09/2010 (7:28 pm)
Thanks Dan. For the most part it will typically be close distance checks so I think I will be safe without that. Would be nice to find a cleaner way to search the mesh list as well as it looks like it is just doing a brute search through all of the points in the list looking for something. Only testing with a small mesh, I would imagine one with 100,000 or more points to search through would be a bit hungry.
#175
01/17/2010 (6:34 pm)
hi dan~
may i ask a question?
i see aiDemo.mis.
but when i create a AIplayer in navigation mesh,
how i use findPathTo the functions??
press ~ use
findPathTo NPCname?? or findPathTo location??
but i try always "<input> (0): Unable to find function findPathTo"
no see anyone move~
can u tell me how do it??
i really very need the functions!

thx a lots and please~
#176
01/18/2010 (5:19 pm)
findPathTo runs in the bot's object namespace. So if the aiplayer object is stored in %bot, you call %bot.findPathTo(location). If you want to find a path to a player object, you would call %bot.findPathTo(%player.getPosition())
#177
02/12/2010 (7:04 pm)
Hey deepscratch

I'm very interested in getting this to work in T3D 1.0 I'm getting errors no matter what I do. Do you still have your working files?
#178
02/19/2010 (11:02 am)
Hi I am trying to implement this into T3D 1.1 BETA but I can't get past the C++ stuff because I keep getting a crap load of errors. I have managed to fix some but there are still more. Here they are

Error 1 error C3861: 'disSqr': identifier not found c:TorqueTorque 3D 2009 Pro 1.1 Beta 1EnginesourceT3DaStar.cpp 256
Error 2 error C3861: 'disSqr': identifier not found c:TorqueTorque 3D 2009 Pro 1.1 Beta 1EnginesourceT3DaStar.cpp 257
Error 3 error C3861: 'disSqr': identifier not found c:TorqueTorque 3D 2009 Pro 1.1 Beta 1EnginesourceT3DaStar.cpp 257
Error 4 error C3861: 'disSqr': identifier not found c:TorqueTorque 3D 2009 Pro 1.1 Beta 1EnginesourceT3DaStarMesh.cpp 378
Error 5 error C3861: 'disSqr': identifier not found c:TorqueTorque 3D 2009 Pro 1.1 Beta 1EnginesourceT3DaStarMesh.cpp 379
Error 6 error C3861: 'disSqr': identifier not found c:TorqueTorque 3D 2009 Pro 1.1 Beta 1EnginesourceT3DaStarMesh.cpp 399
Error 7 error C3861: 'disSqr': identifier not found c:TorqueTorque 3D 2009 Pro 1.1 Beta 1EnginesourceT3DaStarMesh.cpp 400
Error 8 error C3861: 'disSqr': identifier not found c:TorqueTorque 3D 2009 Pro 1.1 Beta 1EnginesourceT3DaStarMesh.cpp 400
Error 9 error C3861: 'disSqr': identifier not found c:TorqueTorque 3D 2009 Pro 1.1 Beta 1EnginesourceT3DaStarMesh.cpp 415
Error 10 error C2065: 'gAStar' : undeclared identifier c:TorqueTorque 3D 2009 Pro 1.1 Beta 1EnginesourcesceneGraphsceneState.cpp 161
Error 11 error C2228: left of '.render' must have class/struct/union c:TorqueTorque 3D 2009 Pro 1.1 Beta 1EnginesourcesceneGraphsceneState.cpp 161
Error 12 fatal error C1083: Cannot open include file: 'T3D/moveManager.h': No such file or directory c:TorqueTorque 3D 2009 Pro 1.1 Beta 1EnginesourceT3DaiPlayer.cpp 8
Error 13 error BK1506 : cannot open file '....LinkVC2k8.Release.Win32test DLLaiPlayer.sbr': No such file or directory BSCMAKE
Error 14 fatal error LNK1181: cannot open input file '......gametest.lib' test
Error 15 fatal error LNK1181: cannot open input file '......gametest.lib' NP test Plugin
Error 16 fatal error C1083: Cannot open include file: 'atlbase.h': No such file or directory c:torquetorque 3d 2009 pro 1.1 beta 1my projectstestwebsourceactivexstdafx.h 19

I can diagnose the problem but I don't know how to fix it (i.e. if there are lines that need to be changed, I don't know what to change them to). I read people have implemented this into T3D before but I don't see how if there are so many errors if possible can some one who has implemented this into T3D help me please.
#179
02/25/2010 (12:16 pm)
Ok you have three problems here. To fix the disSqr thing, add these lines at around 154 in aStar.h
inline F32 disSqr(Point3F a, Point3F b)
{
    return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) + (a.z-b.z)*(a.z-b.z);
}

The gAstar problem is fixed by using the TGEA instructions instead of the TGE ones.

As for moveManager.h, it may be somewhere else in T3D, or it may have been taken out. Try commenting out the line, and if that doesn't work, hunt around.
#180
05/19/2010 (12:41 pm)
This is the best resource yet it is great thanks a heap