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():
Add this in game/tools/missionEditor/scripts/editors/creator.ed.cs line 146:
Add the following function at the end of game/tools/missionEditor/gui/objectBuilderGui.ed.gui:
In [game]/scriptsAndAssets/server/scripts/game.cs, at the end of startGame(), add
At the end of endGame(), add
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
in renderCurrentImages(), around line 481, add the commented code
Save and compile.
In creator/editor/EditorGui.cs, at line 1306, change
to
In creator/editor/objectBuilderGui.gui, at line 643, add
In [game]/server/scripts/game.cs, at the end of startGame(), add
At the end of endGame(), add
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.
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.
About the author
#62
I traced this down to the start of the findBasicPath function (thank you, VSTS profiler!), where it is trying to find the nodes to start and end at:
What this is doing is, for every node in the system it has the potential of doing a CastRay() call twice. This could very well be the case if your AI guy is at the wrong end of the node list in the world (like mine was - I counted over 6,000 CastRay calls a second). The real answer is to create an octtree to hold the nodes, and look through the OctTree, but that's a lot of work and structural change (and has some other negative possibilities as well). So I looked for an easy "good enough for now" answer. (I love that song btw).
First, I added a member to NMPoint to allow me to cache the distance so I only had to calc it once (yeah, it's a minor op, but we'll end up walking the tree several times, and it will help the "worst case" scenarios):
Next, I added a function to find the closest node to a world location, and modified what could block the AI (Basically, I just removed the terrain since this was causing false collisions due to the origin of the models) I also added the ability to skip
collision detection, since I didn't care on the end node whether it was blocked from the projected end or not (he never walks to the actual end anyway, just sits at the end node - probably need to work on that)
Next, I modified findBasicPath to use the function I just created to get the nodes:
Now, That took it down from 6000 CastRay() calls per second to an average of 1. Goodbye, spike!
You can repeat this for most of the other calls also (I haven't touched the SneakUp function...)
Of course this works great for me, but there could be a bug or two in here, all comments and corrections are welcome.
08/19/2008 (8:32 pm)
I've implemented this resource, and it has really been great - Thanks! However, I did notice that it really dragged down my performance in some areas -- every time my AI Guard Unit "thought" in some locations, (every second or so), he would call FindBasicPath, and this would spike the system and cause a hiccup on screen. I traced this down to the start of the findBasicPath function (thank you, VSTS profiler!), where it is trying to find the nodes to start and end at:
for (tmp = list->next; tmp; tmp = tmp->next) //iterate thru list
{
if (disSqr(tmp->loc, Pend) < disSqr(end->loc, Pend) &&
!gServerContainer.castRay(tmp->loc, Pend, STATIC_COLLISION_MASK, &rInfo)) //find closest one
end = tmp;
if (disSqr(tmp->loc, Pstart) < disSqr(start->loc, Pstart) &&
!gServerContainer.castRay(tmp->loc, Pstart, STATIC_COLLISION_MASK, &rInfo)) //find closest one
start = tmp;
}What this is doing is, for every node in the system it has the potential of doing a CastRay() call twice. This could very well be the case if your AI guy is at the wrong end of the node list in the world (like mine was - I counted over 6,000 CastRay calls a second). The real answer is to create an octtree to hold the nodes, and look through the OctTree, but that's a lot of work and structural change (and has some other negative possibilities as well). So I looked for an easy "good enough for now" answer. (I love that song btw).
First, I added a member to NMPoint to allow me to cache the distance so I only had to calc it once (yeah, it's a minor op, but we'll end up walking the tree several times, and it will help the "worst case" scenarios):
struct NMPoint
{
U32 id;
F32 interval;
Point3F loc; //in world space to prevent confusion
NMPoint *adjs[8];
NMPoint *prev, *next; //for linear linked-list behavior
AStarPoint *asp;
NavMesh* mesh;
F32 DisSqr; // New - cache the distances.
};Next, I added a function to find the closest node to a world location, and modified what could block the AI (Basically, I just removed the terrain since this was causing false collisions due to the origin of the models) I also added the ability to skip
collision detection, since I didn't care on the end node whether it was blocked from the projected end or not (he never walks to the actual end anyway, just sits at the end node - probably need to work on that)
#define ASTAR_COLLISION_MASK ( InteriorObjectType | StaticTSObjectType | StaticShapeObjectType )
#define GRIDSIZE 4
#define GATHERSIZE ((GRIDSIZE * 3) * (GRIDSIZE * 3))
NMPoint *AStar::FindClosestPoint(Point3F pPoint, bool CheckCollision)
{
RayInfo rInfo;
NMPoint *end, *bkup, *tmp;
end = bkup = list;
end->DisSqr = disSqr(end->loc,pPoint);
// Calc them one time
for (tmp = list->next; tmp; tmp = tmp->next) //iterate thru list
{
// Calculate the distance only one time
tmp->DisSqr = disSqr(tmp->loc,pPoint);
// get the closest
if (tmp->DisSqr < end->DisSqr)
{
bkup = end;
end = tmp;
}
}
if (!CheckCollision)
return end;
// try the most obvious choice - It works the vast majority of the time.
if (!gServerContainer.castRay(end->loc, pPoint, ASTAR_COLLISION_MASK, &rInfo))
return end;
// try the second closest. Ok, it's a longshot, but finding it was free.
if (!gServerContainer.castRay(bkup->loc, pPoint, ASTAR_COLLISION_MASK, &rInfo))
return bkup;
// Hardly ever gets this far.
// try the child points of the selected node.
// This should be the nodes all around the player.
for (int i=0;i<8;i++)
{
NMPoint *tmp = end->adjs[i];
if (tmp)
{
// this might give us something a little out of order, but isn't that better than casting through all points?
if (!gServerContainer.castRay(tmp->loc, pPoint, ASTAR_COLLISION_MASK, &rInfo))
return tmp;
}
}
// Check the points around the location.
// Very Very small chance we get here.
// Lets gather the nodes all around us (at least the ones we haven't already looked at).
// Yeah, I unrolled the loop. Due to laziness, there is no speed improvement.
for (tmp = list->next; tmp; tmp = tmp->next) //iterate thru list again. That OctTree would be handy here.
{
if (tmp->DisSqr < GATHERSIZE)
{
// Don't add if we've already checked it.
if (end->adjs[0] == tmp) continue;
if (end->adjs[1] == tmp) continue;
if (end->adjs[2] == tmp) continue;
if (end->adjs[3] == tmp) continue;
if (end->adjs[4] == tmp) continue;
if (end->adjs[5] == tmp) continue;
if (end->adjs[6] == tmp) continue;
if (end->adjs[7] == tmp) continue;
if (!gServerContainer.castRay(tmp->loc, pPoint, ASTAR_COLLISION_MASK, &rInfo))
return tmp;
}
}
// Didn't find anything around us at all. We were probably blown completely off the navmesh really far
// by an explosion or something. Probably should look for the closest Navmeshes, and check those for proximity.
// We could Brute Force it, but no guarantee even then. Lets just return the location and see if he can make it
// there on his own.
return end;
// delete the line above, and define the ASTAR_BRUTE_FORCE if you want to go the extra mile to get a node.
#ifdef ASTAR_BRUTE_FORCE
bool found = false;
end = list;
// do it the hard way.
for (tmp = list->next; tmp; tmp = tmp->next) //iterate thru list
{
if (tmp->DisSqr < end->DisSqr)
{
if (!gServerContainer.castRay(end->loc, pPoint, ASTAR_COLLISION_MASK, &rInfo))
{
found = true;
end = tmp;
}
}
}
if (found)
return end;
return NULL;
#endif
}Next, I modified findBasicPath to use the function I just created to get the nodes:
S32 AStar::findBasicPath (Point3F Pstart, Point3F Pend, Vector<Point3F> &Vpoints)
{
#ifdef AI_RENDER
//LastPoints.clear();
#endif
if (!list)
return -1;
if (Pstart == Pend) //may seem stupid, but probably good to do
return 1;
NMPoint *start, *end, *tmp;
start = end = list;
RayInfo rInfo;
start = FindClosestPoint(Pstart,true);
if (!start) return -1;
end = FindClosestPoint(Pend, false); // don't care if the End Node--->end is blocked
if (!end) return -1;
// Remainder of code remains the same as it was
if (start == end)
{
return 1;
}
// ... code deleted for brevity
}Now, That took it down from 6000 CastRay() calls per second to an average of 1. Goodbye, spike!
You can repeat this for most of the other calls also (I haven't touched the SneakUp function...)
Of course this works great for me, but there could be a bug or two in here, all comments and corrections are welcome.
#63
This will cause havoc in the astar code when it goes to Link the new meshes. In tgea, this will cause an assert to be thrown due to a bogus castray(). (you have two distinct nodes at the same point).
To fix this, move the "deletePaths();" call from the endGame() function to the end of the "OnMissionEnded" function in the same script.
08/20/2008 (7:25 pm)
I found an issue in TGEA 1.7.1 (and verified that it also exists in TGE 1.5.2 and AFX 1.1.2) - the Server/Scripts/Game.cs endGame() function is never called when you hit escape and select OK to manually exit a mission. This means that the navmeshes and lists never get cleaned up, and if you load another mission, you will get the last missions navmeshes mixed in with the new one. This will cause havoc in the astar code when it goes to Link the new meshes. In tgea, this will cause an assert to be thrown due to a bogus castray(). (you have two distinct nodes at the same point).
To fix this, move the "deletePaths();" call from the endGame() function to the end of the "OnMissionEnded" function in the same script.
#64
08/23/2008 (11:00 am)
That worked great, Ben. Thanks!
#65
EDIT:
@John: I put TGEA code in the download that has some features and bug fixes Stefan's doesn't. You should use it instead.
@Jaimi: I think the performance gain from only calculating the distances once is offset by the extra memory used to store them. (~1 meg in a large map)
08/25/2008 (4:47 pm)
Thanks, Jaimi, I'll add that to the code when I get a chance.EDIT:
@John: I put TGEA code in the download that has some features and bug fixes Stefan's doesn't. You should use it instead.
@Jaimi: I think the performance gain from only calculating the distances once is offset by the extra memory used to store them. (~1 meg in a large map)
#66
Yeah, I was super iffy on that. I originally had it walking the node list several times, it doesn't make sense now.
08/26/2008 (3:57 pm)
@Dan: Yeah, I was super iffy on that. I originally had it walking the node list several times, it doesn't make sense now.
#67
EDIT: I also put in some minor bug fixes and performance tweaks.
08/28/2008 (11:35 am)
Ok, I added something similar to that to the download. It's much simpler, but should be comparably fast.EDIT: I also put in some minor bug fixes and performance tweaks.
#68
I moved to 1.8 and was going to start working on my AI and figured this would be a good starting point. Looks like with 1.8, the simPath.h has changed and I am getting an error that ";" is missing before smStateBlock. Not familiar with the new stateblock approach so still learning.
12/23/2008 (7:00 pm)
Anybody implemented this yet for 1.8?I moved to 1.8 and was going to start working on my AI and figured this would be a good starting point. Looks like with 1.8, the simPath.h has changed and I am getting an error that ";" is missing before smStateBlock. Not familiar with the new stateblock approach so still learning.
#69
You need to add:
#include "gfx/gfxStateBlock.h"
#include "gfx/gfxVertexBuffer.h"
to the top of simPath.h. That should get it to compile. If you get it working let me know.
12/24/2008 (6:59 pm)
I made an attempt to port to 1.8. I got everything to compile okay, but the bots don't want to move anywhere. Its possible that there is something inside my ai manager that is preventing it from working.You need to add:
#include "gfx/gfxStateBlock.h"
#include "gfx/gfxVertexBuffer.h"
to the top of simPath.h. That should get it to compile. If you get it working let me know.
#70
12/24/2008 (10:24 pm)
Didn't work for me, tons of compile errors now. Will restore and make changes again (and again) in case I missed something.
#71
You need to add:
#include "gfx/gfxStateBlock.h"
#include "gfx/gfxVertexBuffer.h"
to the top of simPath.h
Then you need to go into aStar.h and change:
#include "sim/sceneObject.h"
to
#include "sceneGraph/sceneObject.h"
and change:
#include "sim/simPath.h"
to
#include "sceneGraph/simpath.h"
then go to aStar.cpp and change:
#include "core/bitStream.h"
to
#include "core/stream/bitStream.h"
then change:
if (!fs.open(misName, FileStream::Write))
to
if (!fs.open(misName, Torque::FS::File::AccessMode::Write))
and then change:
if (!fs.open(misName, FileStream::Read))
to
if (!fs.open(misName, Torque::FS::File::AccessMode::Read))
Finally, you need to go back to aStar.cpp and do a replace all. Replace all "min" with "minExtents" and all "max" with "maxExtents". Without the quotes.
Its a pretty clean port. I don't think there is anything else.
12/24/2008 (11:34 pm)
Okay, I have successfully ported this resource to TGEA 1.8. The problem was in my scripts, not with the resource or changes needed for the resource.You need to add:
#include "gfx/gfxStateBlock.h"
#include "gfx/gfxVertexBuffer.h"
to the top of simPath.h
Then you need to go into aStar.h and change:
#include "sim/sceneObject.h"
to
#include "sceneGraph/sceneObject.h"
and change:
#include "sim/simPath.h"
to
#include "sceneGraph/simpath.h"
then go to aStar.cpp and change:
#include "core/bitStream.h"
to
#include "core/stream/bitStream.h"
then change:
if (!fs.open(misName, FileStream::Write))
to
if (!fs.open(misName, Torque::FS::File::AccessMode::Write))
and then change:
if (!fs.open(misName, FileStream::Read))
to
if (!fs.open(misName, Torque::FS::File::AccessMode::Read))
Finally, you need to go back to aStar.cpp and do a replace all. Replace all "min" with "minExtents" and all "max" with "maxExtents". Without the quotes.
Its a pretty clean port. I don't think there is anything else.
#72
Will redo this tonight if I can and give it a try - if you got it working, then I am sure I had something entered wrong. Thanks!
12/25/2008 (8:57 am)
Thanks, will give it a try. Have been trying to get an Atlas2 map to compile in 1.8. But did manage to get it to compile in 1.7 and move over to 1.8. I can live with that for now.Will redo this tonight if I can and give it a try - if you got it working, then I am sure I had something entered wrong. Thanks!
#73
I have made a minor tweak: in AIPlayer.cpp, function AIPlayer::getAIMove()
About line 185:
This will keep the bot from constantly aiming at you, even while moving from point to point behind walls, despite being out of LOS.
12/29/2008 (3:37 am)
Excellent resource, works very well and is very easy to implement. I have made a minor tweak: in AIPlayer.cpp, function AIPlayer::getAIMove()
About line 185:
if (mAimObject)
mAimLocation = mAimObject->getPosition() + mAimOffset;
else
if (!mAimLocationSet)
mAimLocation = mMoveDestination;
//Change above to:
if (mAimObject && mTargetInLOS)
mAimLocation = mAimObject->getPosition() + mAimOffset;
else
if (!mAimLocationSet && !mTargetInLOS)
mAimLocation = mMoveDestination;This will keep the bot from constantly aiming at you, even while moving from point to point behind walls, despite being out of LOS.
#74
When I chose Mission, navmesh...I get a box to assign a name. I assign a name, and the box goes away. THere are no new objects to be seen, not on the game window or the simtree.
In the console, I get
"creator/newobject.cs (0)
unable to instantiate non-conobject Navmesh"
Also, unable to find function readPaths.
I followed the instructions precisely, on a new install of 1.5.2. It was a clean build, unsure what I did wrong.
**EDIT**
Ok, I got it compiled finally. I followed directions on how to setup vc2005 from a post I requested help in. The person told me how, but I didnt know I had to set a debug and release working directory.
I am now able to add a navmesh, build and write paths.
I just have 2 questions.
1. How do I get the bot to spawn on it. What line or lines do I change/add in aiplayer.cs or aiplayer.cc?
2. How do I get the navmesh to render inside and outside. I want bots to be able to chase me inside buildings.
**Edit x 2**
1.
Ok, I was using the default aiplayer.cs. It tells a bot to spawn on the first node of Path1. I drug the first node over the navmesh, he now spawns there and accepts the wonder, and other commands.
It never occured to me path1 was basically an aidrop point. I can make a marker later to fix that. I suck at scripting, but hopefully I can get the bot to wonder constantly and attack when it sees me.
2. I took down the doors on my building, built a mesh and he will indeed run inside, and into any room. Works like a dream. Later I'll try and figure out how to get it to open the doors.
The only problem I have left, if I build a mesh on the second floor, and one on the first floor of the building, I cannot connect them. I have a stairwell with around a 30degree incline. I tried rotating the mesh to match the angle with no luck.
01/15/2009 (12:06 pm)
I'm having a little trouble. When I launch the aidemo, the console lists 0 errors.When I chose Mission, navmesh...I get a box to assign a name. I assign a name, and the box goes away. THere are no new objects to be seen, not on the game window or the simtree.
In the console, I get
"creator/newobject.cs (0)
unable to instantiate non-conobject Navmesh"
Also, unable to find function readPaths.
I followed the instructions precisely, on a new install of 1.5.2. It was a clean build, unsure what I did wrong.
**EDIT**
Ok, I got it compiled finally. I followed directions on how to setup vc2005 from a post I requested help in. The person told me how, but I didnt know I had to set a debug and release working directory.
I am now able to add a navmesh, build and write paths.
I just have 2 questions.
1. How do I get the bot to spawn on it. What line or lines do I change/add in aiplayer.cs or aiplayer.cc?
2. How do I get the navmesh to render inside and outside. I want bots to be able to chase me inside buildings.
**Edit x 2**
1.
Ok, I was using the default aiplayer.cs. It tells a bot to spawn on the first node of Path1. I drug the first node over the navmesh, he now spawns there and accepts the wonder, and other commands.
It never occured to me path1 was basically an aidrop point. I can make a marker later to fix that. I suck at scripting, but hopefully I can get the bot to wonder constantly and attack when it sees me.
2. I took down the doors on my building, built a mesh and he will indeed run inside, and into any room. Works like a dream. Later I'll try and figure out how to get it to open the doors.
The only problem I have left, if I build a mesh on the second floor, and one on the first floor of the building, I cannot connect them. I have a stairwell with around a 30degree incline. I tried rotating the mesh to match the angle with no luck.
#75
I was rolling my own from scratch when I happened upon this article, so now with some custom modifications and tweaking this will save a ton of time so I can focus on more game oriented stuff!
Thanks!
01/20/2009 (11:04 am)
Such a great resource, hats off to you sir!I was rolling my own from scratch when I happened upon this article, so now with some custom modifications and tweaking this will save a ton of time so I can focus on more game oriented stuff!
Thanks!
#76
There is alot to read here but once i get a chance to fully test it out i will go back and read the rest of the posts for things i may need to change.
Good job mate.
01/29/2009 (8:38 pm)
nice resource. thanks a ton. have yet ot fully test it but compiled without error and it ran perfect. no preformance hits at all. There is alot to read here but once i get a chance to fully test it out i will go back and read the rest of the posts for things i may need to change.
Good job mate.
#77
01/31/2009 (8:26 pm)
@Charlie: What happens exactly with the stairs?
#78
Any help?
02/04/2009 (8:47 am)
Hey I'm having a bit of an issue here with aStar.cpp in TGEA 1.7.1. Whenever deletepaths() gets called, either by quitting or manually, it causes a memory access violation error. I've tracked this down to the pointer clean up of the list of paths. For some reason when it deletes the first node it also deletes the second. This makes no sense and explains why trying to do pt->next would cause an access violation.Any help?
#79
02/04/2009 (6:46 pm)
Is this from NavMeshes you've placed or from paths loaded from a file?
#80
Edit: This has also been confirmed as a problem across multiple computers.
02/05/2009 (9:04 am)
It's both. Just so we're looking at the same code, it's in AStarr::deleteall()Edit: This has also been confirmed as a problem across multiple computers.
NMPoint* pt;
for (pt = list; pt->next;)
{
pt = pt->next;
delete pt->prev;
}
delete pt; 
Torque Owner Ben Sparks - Warspawn
StarOrdered Games
in AIPlayer::getAIMove around line 173 comment this out
then modify the movement part back to the original, but add in the part after the else (line 274)
// Check if we should mMove, or if we are 'close enough' // AStar clearence is used to give us enough room to get around corners if (mFabs(xDiff) < tol && mFabs(yDiff) < tol) { if (path.size()) { /*if(mMoveDestination != path[1]) {*/ mMoveDestination = path[0]; path.pop_front(); //} //else { // stopMove(); // throwCallback("onReachDestination"); //} } else { stopMove(); throwCallback("onReachDestination"); } } else { if(path.size()) mMoveState = ModeMove; ...that seems to work I have some script to make them wander or follow the path randomly that I could post as well if needed.