Game Development Community

dev|Pro Game Development Curriculum

AIPlayer - Face Target Before Moving

by Chris Haigler · 04/24/2011 (9:26 pm) · 4 comments

Note: This resource is intended to be used in addition to Daniel Buckmaster's Player Turning Inertia. Daniel's resource modifies the AIPlayer class such that AIPlayers will rotate slowly toward their destination point rather than instantly 'snapping' to face it.

The AIPlayer class separates movement and turning allowing AIPlayers to move and/or rotate simultaneously. In the stock codebase this is perfectly fine because AIPlayers instantly 'snap' toward their intended destinations. Only after implementing Daniel's resource did this become a noticeable issue. In the more extreme cases (i.e. where an AIPlayer is given a low turning speed and also ordered to move to a point behind them), the AIPlayer will appear to move toward their target in reverse while (slowly) turning to face it.

The snippet below fixes this issue by preventing AIPlayers from moving until their target is within the AIPlayer's field of view. If the AIPlayer can't 'see' their target, they will stop moving but continue turning until the target is in the field of view.

Onto the code:

In aiPlayer.cpp (or aiPlayer.cc depending on your Torque product), find AIPlayer::getAIMove(). Within this method, find the following bit of code:
// Check if we should mMove, or if we are 'close enough'
      if (mFabs(xDiff) < mMoveTolerance && mFabs(yDiff) < mMoveTolerance) {
         mMoveState = ModeStop;
         throwCallback("onReachDestination");
      }
      else {

and replace it with:
// Check if we should mMove, or if we are 'close enough'
      if (mFabs(xDiff) < mMoveTolerance && mFabs(yDiff) < mMoveTolerance) {
         mMoveState = ModeStop;
         throwCallback("onReachDestination");
      }
      else {
			// So we need to move to the destination. Let's check to see if we're (roughly) facing the destination.
			// If not, we'll skip the movement stage to give ourselves a chance to turn toward the target. 
			// This prevents AIPlayers from moving toward a target in reverse and turning at the same time (which looks wrong).
			// Note: This is a simple (and fast) 'field of view' check, a ray cast could potentially be more accurate.
			Point3F targetVec;
			targetVec = mMoveDestination - getPosition();
			targetVec.normalize(); // need to normalize the vector so it's a... normal vector.

			F32 dot = mDot(targetVec, getTransform().getForwardVector());

			F32 angle = mDegToRad(90.0f);
			angle = mCos(angle);

			// we now have the view cone going from 90 degrees left of center and 90 degress right of center
			// if our target destination is within this viewport move to it, else ignore movement for now
			if(dot < angle) //target not in view
			{
				return true;
			}

Recompile and you're all set.

Notes and Possible Improvements:
* As indicated by the comment, the snippet above performs a simple 'field of view' test. The size of the view cone can be adjusted by changing the 'F32 angle' variable. Higher values = a wider view cone which will allow the AIPlayer to move sooner. Lower values = a narrower view cone which will force the AIPlayer to really 'hone in' on its target before moving.

Allowing the angle variable to be set/changed without needing a recompile would be a possible improvement.

* Depending on your requirements, a raycast (say, to a point on the target's bounding box) will be more accurate and possibly preferable. The raycast will be slower, though.

* Adding code to enable/disable the FoV check altogether would be another possible improvement.

#1
04/25/2011 (8:45 am)
Perhaps use the FOV angle from the AIPlayer's datablock - that would be terrific.
#2
04/25/2011 (9:56 am)
That would certainly make sense. :] In my case, I'm using this in a custom AIVehicle class (which inherits from a very stripped down/lightweight ShapeBase class) so I don't have access to any of the Player 'stuff'.
#3
04/26/2011 (9:10 am)
Hmm. Yeah, might have to expose it to script yourself (or myself) then. That would be real handy.
#4
03/01/2012 (3:43 pm)
Nice addition. Sometimes I feel like having separate aiming and movement is desirable - it lets AIPlayers strafe around like real players. But depending on your game that's not necessarily a good thing!