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.
#121
08/03/2009 (3:03 am)
Has anyone ever updated the player code to add 'smoother rotation' for players? The AIPlayers always 'snap' to their next direction rather than smoothly turning. Guess we need to add some sort of iteration to the rotation.
#122
08/04/2009 (10:05 pm)
hello everyone
may i ask a question?
when i use the Flexible A* Pathfinding System on TGEA_1_7_1 i got a mistake when I press F11, click World Editor, choose the MissionObjects>Mission>Navmesh, I give it a name, and nothing happens. I open the console, and I have
Tried to get the object for item 106, which is not InspectorData!
Tried to get the object for item 106, which is not InspectorData!
editor/newObject.cs (0): Unable to instantiate non-conobject class NavMesh.

i dunno how to use the function have anyone can help me please!!
#123
08/05/2009 (7:29 am)
My guess is your torque executable doesn't have all the code changes needed.

Did you add all the c++ code to your project and recompile? Are you running the exe that you compiled and not the other one? (If the dropdown box at the top of visual studio says "debug," it will have _DEBUG at the end)
#124
08/12/2009 (10:13 pm)
I'm trying to get this to work with Torque 3D as it seems like a wonderful pathing tool; could anyone explain how it's done please? Thank you!
#125
08/13/2009 (8:17 am)
Unfortunately I don't own T3D so you're on your own here.
#126
08/17/2009 (7:53 am)
@Jinnie

I can't imagine there are that many changes required to get this running in T3D since there is a TGEA version.
#127
09/27/2009 (8:20 am)
well, it was a breeze to get it working in T3D.

but I keep getting this error when trying to get them to wander
==>bob.wander(20);
<input> (0): Unknown command wander.
  Object bob(1051476) bob -> StaticShape -> ShapeBase -> GameBase -> SceneObject -> NetObject -> SimObject
ideas?

img43.imageshack.us/img43/7433/navmesht3d.jpg

EDIT: staring me in the face, my bots are created as StaticShapes, not players. duh.
#128
09/27/2009 (10:49 am)
awesome, works a treat, except...
why do my bots do all their moving about backwards? ie facing the wrong way?
#129
09/27/2009 (10:58 am)
Moving backwards is weird, are you sure your models are facing in the Y+ direction in the editor?

From the
Object bob(1051476) bob -> StaticShape -> ShapeBase -> GameBase -> SceneObject -> NetObject -> SimObject
it looks like bob is a StaticShape instead of an AIPlayer. Do the other functions work?
#130
09/27/2009 (11:01 am)
I got all the functions to work,
I was first calling the spawn id, not the bot id, now calling the bot id works fine, but all the functions make the bots walk backwards.
the model is correctly set up, yes.

NOTE: this is in T3D, dunno if its relevent
#131
09/27/2009 (11:02 am)
I have no idea. Maybe it's a T3D thing, or maybe it's a problem with your datablocks.
#132
09/27/2009 (11:03 am)
mm, I'll have to check deeper.
Dan, awesome resource btw.
#133
09/27/2009 (11:14 am)
ahh, ok, I see the issue,
its not backwards,
its that when he starts to perform a function, he doesnt turn, he constantly faces in the direction he was facing when the command began.
so he doesnt turn to face a forward direction when moving

EDIT: it seems, when he moves to a new position, he always faces his spawn point, his original position, not the next node.
#134
09/27/2009 (7:35 pm)
A clearAim() or setAimObject() call required perhaps?
#135
09/28/2009 (7:10 am)
ok,
its a problem with my scripts,
I'll have to change my %obj.setAimLocation settings with an "if" for when they are pathing.
otherwise all works 100%
yay.
right then, into script land we go....
#136
09/28/2009 (8:59 am)
any kind soul willing to share a script showing the functions in action?
I'm just not getting my head around it.
#137
09/29/2009 (6:58 am)
hi all
when i compiling always meet this problem...
maybe i system set error ? or need edit code?
i use TGEA1.7.1 @@


1>------ Build started: Project: Template, Configuration: Debug Win32 ------
1>Compiling...
1>aStar.cpp
1>c:\torque\tgea_1_7_1\engine\source\t3d\astar.h(7) : fatal error C1083: Cannot open include file: 'sim/sceneObject.h': No such file or directory
1>sceneState.cpp
1>c:\torque\tgea_1_7_1\engine\source\t3d\astar.h(7) : fatal error C1083: Cannot open include file: 'sim/sceneObject.h': No such file or directory
1>Generating Code...
1>Creating browse information file...
1>Microsoft Browse Information Maintenance Utility Version 8.00.50727
1>Copyright (C) Microsoft Corporation. All rights reserved.
1>BSCMAKE: error BK1506 : cannot open file '..\..\link\vc2k5.debug.win32\template\sceneState.sbr': No such file or directory
1>Build log was saved at "file://c:\Torque\TGEA_1_7_1\Projects\Template\buildFiles\Link\VC2k5.Debug.Win32\Template\BuildLog.htm"
1>Template - 3 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 8 up-to-date, 0 skipped ==========
#138
10/04/2009 (3:44 am)
Hey deepscratch, you have to do anything special to get the blue grid to show up in T3D? Ive only been able to get the vertical green lines to render.
#139
10/04/2009 (9:13 am)
Adam - If you have the green nodes showing up. Then I think all you need to do is type "buildpaths();" in your console and the mesh should appear.

One other thing is to look in sceneState.cpp and make sure this is in the right place.
renderPass->sort();
   renderPass->render(this);
   //aStar   
   #ifdef AI_RENDER   
    gAStar.render(this);   
   #endif   
   //aStar   
   renderPass->clear();

   mInteriorList.clear();

edit: forgot to mention the global.
$Pref::AStar::Render = "1" should be in your prefs.

good luck!!
#140
10/04/2009 (3:58 pm)
Thanks Freeze, that did it.