Game Development Community

AIPlayer onStuck callback bug (?) and it's fix

by Kent Butler · in Torque Game Engine · 09/24/2007 (3:34 pm) · 3 replies

I couldn't find this referenced anywhere so I decided to post it (hopefully I picked the correct place?).

I've been working with the AI player a bit and ran into an issue - I'm pretty sure a bug. The onStuck callback does not get executed - even when the AIPlayer is stuck :) The problem turned out to be in the AIPlayer::getAIMove function (aiPlayer.cc). There were actually two problems.

1: The mLastLocation variable that is used to see if the bot is stuck never gets assigned a value (so of course the stuck check fails).

2: In my case, just setting the value also failed. For some reason there can be micro-moves when the aiPlayer is stuck, especially on the z axis and the logic as written compares all three axis values. Doing a direct comparison between just the x and y values ultimately WORKED but it still took a second for x/y fluctuations to sort themselves out - dunno why.

The best fix I found was to filter micromoves in the logic and set the mLastLocation variable if the aiPlayer is not stuck. I use the same logic as with the onReachDestination callback substituting the commonly used .01 (seemed perfect) threshold to decide if movement occurred.

the fix I used:

in player.cc, change this (in bold):
bool AIPlayer::getAIMove(Move *movePtr)
{
   *movePtr = NullMove;
     .
     .
     .
		 else {
                     movePtr->x *= mMoveSpeed;
                     movePtr->y *= mMoveSpeed;
		 }
		  // We should check to see if we are stuck...
[B]
         if (location == mLastLocation) {
            throwCallback("onMoveStuck");
            mMoveState = ModeStop;
         }
[/B]

to this (also in bold)
bool AIPlayer::getAIMove(Move *movePtr)
{
   *movePtr = NullMove;
     .
     .
     .
		 else {
                     movePtr->x *= mMoveSpeed;
                     movePtr->y *= mMoveSpeed;
		 }
		  // We should check to see if we are stuck...
[B]
		  // KGB: Bugfix - set the mLastLocation variable and
		  //      filter microMoves.
		  xDiff = mLastLocation.x - location.x;
		  yDiff = mLastLocation.y - location.y;
		  F32 zDiff = mLastLocation.z - location.z;      // Recommended by Brian West
		  if (mFabs(xDiff) < .01f && mFabs(yDiff) < .01f && mFabs(zDiff) < .01f) {
			 mMoveState = ModeStop;
			 throwCallback("onStuck");
		  }else{
			mLastLocation = location; // <-- hey kids, always set your comparison variable
		  }
		  // KGB: End bugfix
[/B]

I suspect onStuck isn't used much for serious AI - but for a quickie demo, it's pretty handy.

Updated almost immediately to add a zDiff check

#1
09/24/2007 (3:51 pm)
Excellent! I was looking at this exact piece of code last night. I just wasn't ready to try and do anything about it.

Thanks!


Edit: One question.. Should we really filter the Z movement? What if the AI is falling in place? Lets say I drop him straight down into the world from on high.. He would be falling for a while but he would think he is stuck. Can we just add the zDiff check in there?
#2
09/24/2007 (4:52 pm)
You have a very good point. Yes, it should work to add a zDiff check and would probably be more thorough. The movement routine is only x/y so I just kept to that without really thinking.

Note: Played with it a bit ... I'm having a hard time getting my AIPlayer to just drop while following a path without some x/y movement. I assume that if it ever does that it would become "stuck". I'm kind of curious if I can encounter a situation where that will happen, so I'm gonna leave mine just x/y for the moment.
#3
09/25/2007 (2:50 am)
I agree that its not likely to happen but it *could*. The only one I could think of is if you spawned an AI high off the ground.