Walkabout Navigation Toolkit help thread
by Daniel Buckmaster · in General Add-On Discussion · 11/08/2012 (3:57 pm) · 223 replies
This is the official Walkabout help thread. If you need a hand installing or using Walkabout, please ask away! But before you do, I'd really appreciate if you could follow a couple of guidelines:
- Re-read the installation instructions! Seriously, I know how often I run into some ridiculous issue, then realise I'd missed a step or misread a line. It helps me and you!
- If you're reporting an error in compilation, please tell me the errors you get and what files they're in, if you can!
- If you're reporting a bug, please provide steps I can take to reproduce it!
Known issues
- Release 1 Patch 3: no navmeshes appear in the browser list in the nav editor. Fix
- Engine version > 3.5.1: project generator scripts are incorrect. Fix. Also, be sure not to include the Recast module in your project configuration!
- On platforms that are not Windows, you may need to replace FLT_MAX with F32_MAX. In fact this is probably a good idea in Windows as well.
About the author
Studying mechatronic engineering and computer science at the University of Sydney. Game development is probably my most time-consuming hobby!
#162
03/07/2014 (5:42 am)
ok i'll try that, thanks again dan...
#163
hope thats a good spot, now for scripting.....
03/07/2014 (6:38 am)
Ok dan got it to compile with no errors, thank you very much, I moved it to here;void repath();
/// Get cover we are moving to.
CoverPoint *getCover() { return mCoverData.cover; }
bool findCover(const Point3F &from, F32 radius);hope thats a good spot, now for scripting.....
#164
if i can get the size to workout then i plan on using this to set the poses...
If this is all wrong or a bad idea plz by all means tell me....
03/07/2014 (11:21 am)
Dan, you said if I knew the handle I could access the size of the coverpoint in question... I have each coverpoint named A thru N, how can I obtain the name of the coverpoint?? I tried getName to no aval!! also heres my idea for setting the pose accordingly...//Get Player position...
%position = LocalClientConnection.getControlObject().getPosition();
// Try to take cover....
%this.findCover(%position, $AISK_WALKABOUT_COVER_RADIUS);
//Get CoverPoint Name
%coverName = %this.getName();
%cover = %this.findCover(%position, $AISK_WALKABOUT_COVER_RADIUS);
if(%cover != -1)
{
%pose = %coverName.size;
echo("Cover:" @%cover);
echo("CoverName:" @%coverName);
echo("Pose:" @%pose);
}if i can get the size to workout then i plan on using this to set the poses...
function AIPlayer::SetCoverPose(%obj)
{
// If cover pose is Stand, we set AIPlayer pose to 0
// If cover pose is Crouch, we set AIPlayer pose to 1
// If cover pose is Prone, we set AIPlayer pose to 2
// Default cover pose is stand.....
switch$(%obj.action)
{
case "Stand":
%obj.setAIPose(0);
case "Crouch":
%obj.setAIPose(1);
case "Prone":
%obj.setAIPose(2);
default:
%obj.setAIPose(0);
}
}If this is all wrong or a bad idea plz by all means tell me....
#165
03/12/2014 (7:22 pm)
OK need help bad, tried everything to get %cover.size to no aval???
#166
03/13/2014 (5:27 am)
Sorry Donnie, I meant to get back to you! There's some stuff going on in that fragment you posted. I've added some of my own comments.// Ok this is fine. Get the player's current position.
%position = LocalClientConnection.getControlObject().getPosition();
// This will make the AIPlayer immediately run to cover, and return
// the cover point that was found.
%this.findCover(%position, $AISK_WALKABOUT_COVER_RADIUS);
// Okay, now this line, which seems like you want to get the name
// of the cover point, actually gets the AIPlayer's name, because
// %this is the AIPlayer this method is called on. Same as in the line
// above.
%coverName = %this.getName();
// Okay, this is closer - this time you capture the cover object
// that was found by the search. But this call makes the first call
// redundant!
%cover = %this.findCover(%position, $AISK_WALKABOUT_COVER_RADIUS);
// Yep, good, make sure that cover was actually found.
if(%cover != -1)
{
// Okay, so currently coverName is set to the name of the AIPlayer.
// You probably want to use %cover here, since that refers to the
// actual cover object.
%pose = %coverName.size;
echo("Cover:" @%cover);
echo("CoverName:" @%coverName);
echo("Pose:" @%pose);
}
#167
this is what i have in code??
03/13/2014 (7:16 am)
Hey dan, thank you for explaining, %cover is the only thing that echos anything..... this is the console!Cover:1 Pose: Cover Size:
this is what i have in code??
%cover = %this.findCover(%position, $AISK_WALKABOUT_COVER_RADIUS);
if(%cover != -1)
{
%pose = %cover.size;
echo("Cover:" @%cover);
echo("Pose:" @%pose);
echo("Cover Size:" @%cover.size);
}
#168
03/13/2014 (8:34 am)
Hey, just for giggles, try this:%cover = %this.findCover(%position, $AISK_WALKABOUT_COVER_RADIUS);
if(%cover != -1)
{
// %cover should be an object, right?
if(!isObject(%cover))
echo(" !! %cover is not an object");
%pose = %cover.size;
echo("Cover:" @%cover);
echo("Pose:" @%pose);
echo("Cover Size:" @%cover.size);
}That way if findCover() isn't returning an object it will be readily apparent. It looks like it's returning "true" instead of the object to hide behind.
#169
03/13/2014 (8:49 am)
Hey Richard, your right, findcover is not returning an object??? ok now im confused.... lol
#170
03/13/2014 (1:49 pm)
i tried everything, getting coverpoint to set ai pose will be great when we get it working. I cant say enough about this kit dan, awsome as ever and thank you so much for your hard work on it....
#171
03/13/2014 (3:13 pm)
Donnie, can you try changing $AISK_WALK... to 0? As in try to find cover with 0 radius. What does it return? I suspect the changes to findCover aren't working, and it's returning 1 (true) instead of an object.
#172
03/13/2014 (8:06 pm)
Hey Dan, I set the global to 0 and it still isnt returning an object. Cover still returns as a 1 and the bot didnt seek cover..... Set my global back up and he seeks cover and still not returning the coverpoint as an object...
#173
Experimented with
With a trigger once every few cycles per-bot using https://github.com/Azaezel/Torque3D/commits/AI_manager in a 64MB queue (meaning it waits 64 seconds * botcount between bot decisions to keep from flooding the place.). UNfortunately, due to the frequency of the redraw, even at 1 unit density, it ended up leaking like a sieve.
03/14/2014 (9:42 pm)
Ok, so this is a bit long and involved: looked a bit into http://www.stevefsp.org/projects/rcndoc/prod/group__crowd.html, but that didn't seem terribly suited to the engine without some hefty reworks.Experimented with
DefineConsoleFunction(WalkaboutIgnore, void, (S32 objid, bool _ignore), (0, true),
"@brief Flag this object as not generating a navmesh result.")
{
SceneObject *obj;
if(!Sim::findObject(objid, obj))
return;
obj->mPathfindingIgnore = _ignore;
}+static void buildCallback(SceneObject* object,void *key)
{
SceneContainer::CallbackInfo* info = reinterpret_cast<SceneContainer::CallbackInfo*>(key);
if (!object->mPathfindingIgnore)
object->buildPolyList(info->context,info->polyList,info->boundingBox,info->boundingSphere);
}+getContainer()->findObjects(box, StaticObjectType | DynamicShapeObjectType, buildCallback, &info);
With a trigger once every few cycles per-bot using https://github.com/Azaezel/Torque3D/commits/AI_manager in a 64MB queue (meaning it waits 64 seconds * botcount between bot decisions to keep from flooding the place.). UNfortunately, due to the frequency of the redraw, even at 1 unit density, it ended up leaking like a sieve.
#174
Now I'm thinking a more proper methodology would be more along the lines of either treating players as tempobstacles (http://digestingduck.blogspot.com/2011/04/temporary-obstacle-progress.html), or an additional variant on walkaboutupateall that takes a vector of objects and flags a series as dirty to be redrawn in a second step). Anyone look into other resolutions for dynamic avoidance?
03/14/2014 (9:43 pm)
At present, ended up settling for retooling our old racing ai code like so:bool AIPlayer::getAIMove(Move *movePtr)
{...
movePtr->x = newMove.x;
movePtr->y = newMove.y;
mNextDodge--;
if ((mDodge)&&(mNextDodge <=0))
{
mNextDodge = mDodgeCycle;
Point3F avoidanceOffset = avoidCollisions();
if (!avoidanceOffset.isZero())
{
mMoveState = ModeMove;
movePtr->x += avoidanceOffset.x * mDodgeCycle;
movePtr->y += avoidanceOffset.y * mDodgeCycle;
}
}+Point3F AIPlayer::avoidCollisions()
{
disableCollision();
F32 thetaScale = TickSec * mDodgeCycle; //think mDodgeCycle ticks ahead
Point3F start = getBoxCenter();
Point3F feeler,temp;
F32 velocity = getVelocity().len() * thetaScale;
if (velocity <= mMoveTolerance) velocity = mMoveTolerance; //avoid divnull
Point3F ForwardRot,LeftRot,RightRot;
getTransform().getColumn(0,&LeftRot);
getTransform().getColumn(1,&ForwardRot);
RightRot = -LeftRot;
Point3F frontFeeler = (ForwardRot * velocity) + start;
frontFeeler.z = start.z;
Point3F leftFeeler = (LeftRot * velocity) + start;
leftFeeler.z = start.z;
Point3F rightFeeler = (RightRot * velocity) + start;
rightFeeler.z = start.z;
// Find closest intersection with objects
bool intersectionFound = false;
RayInfo closestRay;
FeelerState closestFeelerState = Open;
RayInfo rayInfo_1;
closestRay.distance = rayInfo_1.distance = (frontFeeler-start).len();
if (gServerContainer.castRay( start, frontFeeler, AIPLAYER_LOSMASK , &rayInfo_1 ))
{
if (rayInfo_1.distance > closestRay.distance)
{
closestRay = rayInfo_1;
intersectionFound = true;
closestFeelerState = FrontFeeler;
}
}
RayInfo rayInfo_2;
rayInfo_2.distance = (leftFeeler-start).len();
if (gServerContainer.castRay( start, leftFeeler, AIPLAYER_LOSMASK , &rayInfo_2 ))
{
intersectionFound = true;
if (rayInfo_2.distance < closestRay.distance)
{
closestRay = rayInfo_2;
closestFeelerState = LeftFeeler;
}
}
RayInfo rayInfo_3;
rayInfo_3.distance = (rightFeeler-start).len();
if (gServerContainer.castRay( start, rightFeeler, AIPLAYER_LOSMASK , &rayInfo_3 ))
{
intersectionFound = true;
if (rayInfo_3.distance < closestRay.distance)
{
closestRay = rayInfo_3;
closestFeelerState = RightFeeler;
}
}
//determine rotated offset to pad our movement by
Point3F offset;
if (!intersectionFound)
{
offset = Point3F(0.0,0.0,0.0);
}
else
{
mMoveState = ModeMove;
switch (closestFeelerState){
case FrontFeeler:
offset = Point3F(0.0f, closestRay.distance,0.0);
break;
case LeftFeeler:
if (closestRay.distance >0)
{
offset = Point3F(-closestRay.distance, rayInfo_1.distance/2,0.0);
break;
}
case RightFeeler:
if (closestRay.distance >0)
{
offset = Point3F(closestRay.distance, rayInfo_1.distance/2,0.0);
break;
}
}
}
enableCollision();
return offset;
}+function AIData::onCollision(%this, %obj, %col, %vec, %vecLen)
{
Parent::onCollision(%this, %obj, %col, %vec, %vecLen);
%pos = %obj.getPosition();
%offset = vectorScale(%vec, %vecLen * -1);
%pos = vectorAdd(%pos,%offset);
%obj.setMoveDestination(%pos);
}Now I'm thinking a more proper methodology would be more along the lines of either treating players as tempobstacles (http://digestingduck.blogspot.com/2011/04/temporary-obstacle-progress.html), or an additional variant on walkaboutupateall that takes a vector of objects and flags a series as dirty to be redrawn in a second step). Anyone look into other resolutions for dynamic avoidance?
#175
03/14/2014 (9:58 pm)
Yes, using temp obstacles is definitely the ideal solution. I do wonder if there's value in an alternative system that allows regular dynamic objects to be reflected in the navmesh build. This might be nice in the case of, for example, a vehicle that parks and can be jumped on top of.
#176
03/15/2014 (1:28 am)
As far as it goes, there is a:dtObstacleRef dtTileCache::addObstacle(const float* pos, const float radius, const float height, dtObstacleRef* result) and dtObstacleRef dtTileCache::removeObstacle(const dtObstacleRef ref)pair. Coming up blank at present on how to tie that back into the engine, however.
#177
03/16/2014 (4:04 am)
Donnie: that suggests to me that the changes I had you make to findCover aren't taking effect. Can you use Visual Studio to set a breakpoint in the findCover console function and step through it? Would be helpful to know what goes on.
#178
03/16/2014 (8:01 am)
Will do Dan and report back....
#179
03/16/2014 (10:47 am)
Hey Dan, I noticed when I step thru the code in VS it shows a bunch of missing rtti file??? dont know if that matters or not and it is enabled but also in the do not look for f:\dd\vctools\crt_bld\self_x86\crt\prebuild\eh\rtti.cpp...... My knowledge is very limited in c++ but im trying...lol I set a break on findcover and step thru the program but I dont see any variables in the output window, it just goes thru the program as I step??? what should I be looking for exactly?? Sorry for being a pain and thank you for your help and patience....
#180
dynamic_cast does depend on rtti file and I dont have it...
03/16/2014 (11:11 am)
Dan could it be this??static void findCoverCallback(SceneObject *obj, void *key)
{
CoverPoint *p = dynamic_cast<CoverPoint*>(obj);dynamic_cast does depend on rtti file and I dont have it...
Torque Owner Daniel Buckmaster
T3D Steering Committee