Previous Blog Next Blog
Prev/Next Blog
by date

Plan for Stefan Beffy Moises

Plan for Stefan Beffy Moises
Name:Stefan Beffy Moises
Date Posted:May 12, 2004
Rating:4.0 out of 5
Public:YES
Comments:YES
RSS Feed:GarageGames Blog feedor Subscribe with .
Profile Page:View profile page for Stefan Beffy Moises

Blog post
Working on the navgraph and pathfinding for the AI project...
Since Justin is very busy at the moment and "on the road" quite often I've taken over his pathfinding code to tweak and optimize it a bit (not necessarily speed-wise since Justin already did a great job and a lot of tweaking and profiling there, but to get it more versatile and flexible for various map types and map "anomalies" :P).
What anomalies you ask? Well, stuff like the following... :)

Large static obstacles



Look at those rocks, they were one of the problem we've encountered while running a Realm Wars test map... the rocks just werent detected, whereas other statics, like trees, were... so the AI would just bump into those rocks since the Navmesh passed right through them... First, I expected a problem in the fact that the rocks are inside the worldbox of other objects (interiors in this case), but then it turned out to be a simple raycast problem - we were scanning from BOT_HEIGHT (size of the AI Player) down to right above the ground to detect obstacles... well, but those rocks were slightly higher than the AI Player and they stuck inside the terrain - ergo, the rayscan would completely take place inside the rock and never detect anything... :P
So a solution would be to scan from high above in the sky down to the terrain (or even below it) - but what if you have something like a bridge (DTS or DIF), and the AI could walk below that bridge?
Well, the solution I came up with is this: using 3 rayscans for each "terrain node filter" (we are running every node through filters to filter nodes that are too steep, below the terrain, below interiors or statics and the player cant stand there, etc.), so for each node, 3 raycasts are performed now:
1) one down from high above scanning for the terrain height
2) one rayscan up from below the terrain to detect anything else above the terrain - then we check the "free space" between terrain and the (bottom of the) object above it... if the bot is able to stand there, we're almost golden
3) finally, we scan from above again to detect interiors or statics and see if anything sticks in the ground, but also is looking out of the terrain which could be a potential obstacle (e.g. rocks or trees)

Now this does look better, doesn't it?



Fences and other bad things



Here is another favourite problem... the bot would find paths that lead right through the left and right parts of such a fence, since the Nodes are linked mainly based on LOS, so Nodes are connected in cases like this although the bot can only pass that fence in the middle part...

Here is what it looks like now:

The trick here is that the fence luckily consisted of three parts... so I was able to treat each part differently - the middle part is treated like any other interior, the algorithm tries to place nodes inside of it and in a dense grid around it - the left and right parts of the fence however are treated as "blockers" - you can set a flag in the mission editor and there will be no nodes generated inside or around the objects and so no links are created either :)

So, as you can see, the level designer has to be careful how he sets things up in the mission and also how critical interiors are build in Quark/Hammer etc.


The impossible path

One mystery Justin was able to solve yesterday are "impossible" paths... due to the concept of our NavMesh, we have partial meshes on roof tops, etc. (which we could remove, but we think it makes sense to keep them, since somebody may want to place some AI entities on roofs and let them attack from there, etc.)
Anyhow, these nodes are kinda "isolated" from the main navgraph nodes and you end up having nodes on some other weird locations from time to time... e.g. on this well:

Now, if the target or start node of the AI is right at that well e.g., it may pick one of those isolated nodes on top of it as the next nearest node and try to path to/from there, which will fail miserably... starting from there, it will come to an end very soon and give up... trying to path to that node is even worse, since it will try to get there forever and will of course never reach it! This was causing some severe lockups and would slow everything down... so since we dont want to remove those "roof type" nodes, we decided to limit the search to a maximum iterations value for now... if it loops through the main pathfinding algorithm for more than X times, we cancel the search and "give up" on that path...

The mysterious subterranean node

EDIT: well, one more thing since this also was a little mystery ;)
When standing right in front of one of the RW towers, the bot seemed to be unable to find any path... so I checked which node it was using as its start node: it was node with ID 3047:



Now, for some weird reason, there seemed to be no node at that spot where the ID was rendered... hm... after flying around a bit in the mission editor, I found it: there was a group of isolated nodes created under the terrain, covering the basement of the tower! duh!
The bot was chosing one of those as starting point, but of course couldnt get anywhere since the nodes there werent really connected to the main graph again!



For now I just remove any interior node that is under the terrain... but I guess we should support support "underground" interiors so maybe I'll add another flag to interiorInstances to keep those nodes or something like that ...

Phew, that was a long .plan and I still could show you some more anomalies and funny pathfinding pics... but I guess I'll do that in the next .plan ;)
So stay tuned! :)

Recent Blog Posts
List:05/20/08 - Horsepack TGEA 1.7.0 update!
10/15/07 - Free giveaway for horsepack owners - "accouterments of knighthood" horse armor
10/06/07 - "Seawolf" Submarine Content Pack available NOW!
07/06/07 - Horsepack TGEA port, Seawolf Submarine progress
06/04/07 - AI Antelope - Sealife/Submarine Pack - PodRacer Pack
05/24/07 - "Project: Seawolf" - Submarine / Sea Life Content Pack by the 3D-Diggers
04/25/07 - Horsepack released!!
04/15/07 - Horsepack revisited!

Submit ResourceSubmit your own resources!

Mathieu   (May 12, 2004 at 11:09 GMT)   Resource Rating: 5
I really like this kind of .plan.
Great job guys!

John Vanderbeck   (May 12, 2004 at 11:53 GMT)
Been watching this with avid interest for a while now and can't wait to see how it turns out. Navmeshes are very nice for many pathfinding problems. This is looking really great and you guys are doing an awesome job!

Nicolas Quijano   (May 12, 2004 at 14:14 GMT)
Keep up the quality Torquin' Beffy ;)

Cameron Aycock   (May 12, 2004 at 14:24 GMT)
You never cease to amaze me Beefy. Kick ass. I hope to do some testing with yall in the near future, as soon as I get some more game play nailed down.

Ben Garney   (May 12, 2004 at 15:38 GMT)
Nice work, Beffy! And the .plans are REALLY informative. Thanks for putting the effort into them.

Stefan Beffy Moises   (May 12, 2004 at 20:19 GMT)
Thanks guys, glad you like it :)
As a matter of fact, those plans also help me to remember what I did and why and also to think about possible alternatives etc. - so it really helps to write one every once in a while :)
One thing I forgot to mention is the concept of "navmesh blockers" - you can add a marker objects (for now only rectangular, but I will probably add circle shapes, too) and "slice" the navmesh with them to mark unpassable areas in your map (e.g. holes you dont want the AI to walk in, lava regions, etc.):



there is one little problem though, at the moment it seems that you can't put them over interiors since the interior node creation is crashing while doing its raycasts then, which is really weird... gotta figure that one out... I'm using a standard "MarkerObjectType" for it and just copied the standard marker to use as a base - so if anyone has some pointers why this may be happening, let me know :)

Paul Dana   (May 12, 2004 at 22:16 GMT)
Really nice work Beff. I was glad to be of assistance.

Stephen Clark   (May 12, 2004 at 22:33 GMT)
Wow, wow... Its very nice to see some hard-core CS/AI stuff going down w/ Torque. Way to go!

-s

Prairie Games   (May 13, 2004 at 01:17 GMT)
Sehr gemacht!

Cameron Aycock   (May 13, 2004 at 04:54 GMT)
Beffy, I apoligize for always calling you Beefy. Sheesh. A friend of mine pointed that out to me. I think I read it wrong the first time, and "stuck" it in my head.

;)

Dylan Sale   (May 13, 2004 at 12:42 GMT)
I like it! Cannot wait.

Stefan Beffy Moises   (May 13, 2004 at 13:38 GMT)
Hm, putting NavmeshBlockers over interiors does work now... dunno why it would crash before... so forget the above question/comment :)

Another thing is still bugging me though...

Scaled Interiors

I've never done that, but there seem to be folks who scale interiors (DIFs) in-engine/in the mission editor... this seems to screw a lot of things up, e.g. the object box isnt scaled with them and therefore (?) collision doesnt work as expected etc. - and, more important to me, the navgraph generation isnt working for scaled interiors either... here is how the navmesh would look for them:



We are using the objBox of the interiors to place all nodes in object space, and as you can see, the box isnt scaled with the interior... :/


      Box3F box = interiors[i]->getObjBox();


Now, I figured I could just scale the box accordingly, and I took some code from worldEditor.cc (and the help of Paul Dana - thanks dude! :)) to do this... it basically looks like this:

      Box3F objBox = interiors[i]->getObjBox();
MatrixF mat = interiors[i]->getTransform();
VectorF scale = interiors[i]->getScale();

Point3F projPnts[8];
for(U32 j = 0; j < 8; j++)
{
Point3F pnt;
pnt.set(BoxPnts[j].x ? objBox.max.x : objBox.min.x,
BoxPnts[j].y ? objBox.max.y : objBox.min.y,
BoxPnts[j].z ? objBox.max.z : objBox.min.z);
// scale the point
pnt.convolve(scale);
projPnts[j] = pnt;
}
// now find min and max values for our new Box3F
Point3F min,max;
min = projPnts[0];
max = projPnts[0];

for (U32 k=0; k<8; k++)
{
if (projPnts[k].x < min.x)
min.x = projPnts[k].x;
if (projPnts[k].x > max.x)
max.x = projPnts[k].x;
if (projPnts[k].y < min.y)
min.y = projPnts[k].y;
if (projPnts[k].y > max.y)
max.y = projPnts[k].y;
if (projPnts[k].z < min.z)
min.z = projPnts[k].z;
if (projPnts[k].z > max.z)
max.z = projPnts[k].z;
}

// ok, this should hold the scaled objBox now:
Box3F box(min, max);


So far, so good... but unfortunately, this crashes the engine... I've printed out the box values and they all look good, but for some reason it just crashes while doing raycasts inside the interior to generate the Nodes...
the final crash is at interior.h, 683:

inline bool Interior::isBSPLeafIndex(U16 index) const

called from interiorCollision.cc, line 289:

bool Interior::castRay_r(const U16      node,
const U16 planeIndex,
const Point3F& s,
const Point3F& e,
RayInfo* info)

the RayInfo passed in here seems to be invalid... so I guess there really are some serious collision problems with scaled interiors... does anybody have any insights on scaling interiors and collision?
Edited on May 13, 2004 13:42 GMT

Trent Reimer   (May 13, 2004 at 22:15 GMT)
I've said it before and I'll say it again, this is huge! Good work! Strong AI players open up so many possibilities.

Are you going to be releasing this resource to the community?

Stefan Beffy Moises   (May 14, 2004 at 06:30 GMT)
Yes, this stuff will be released to the community (in the next few months probably).

You must be a member and be logged in to either append comments or rate this resource.