Game Development Community

dev|Pro Game Development Curriculum

Mob Look

by Erik Madison · 07/30/2008 (3:18 pm) · 7 comments

If you have AFX installed, you have the beginnings of some very cool control over your AI's head. In my playing around, I have an AIGuard who truly scans, looking left and right without jumping his body around in circles.

Again, you must be using AFX. I merely built upon the >> player-look code.
player.h
[i]public, under setLook....[/i]
   void         setHeadRotation(F32);
   void         setHeadAngle(F32);
   // called 2, as its pretty different than stock one
   F32          getHeadRotation2() { return headHLookOverridePos; }
   F32          getHeadAngle()     { return headVLookOverridePos; }

player.cpp
void Player::setHeadRotation(F32 pos)
{
  headHLookOverridePos = pos;
  setMaskBits(LookOverrideMask);
}

void Player::setHeadAngle(F32 pos)
{
  headVLookOverridePos = pos;
  setMaskBits(LookOverrideMask);
}

ConsoleMethod(Player, setHeadRotation, void, 3, 3, "setHeadRotation(thread pos) Left-Right")
{
  object->setHeadRotation(dAtof(argv[2]));
}

ConsoleMethod(Player, setHeadAngle, void, 3, 3, "setHeadAngle(thread pos) Up-Down")
{
  object->setHeadAngle(dAtof(argv[2]));
}

ConsoleMethod(Player, getHeadRotation, F32, 2, 2, "returns 0-1")
{
  return object->getHeadRotation2();
}

ConsoleMethod(Player, getHeadAngle, F32, 2, 2, "returns 0-1")
{
  return object->getHeadAngle();
}
Find the underutilized LookOverrideMask in the pack/unpack and add the following
stream->writeSignedFloat(headVLookOverridePos/* / mDataBlock->maxLookAngle*/, 6);
     stream->writeSignedFloat(headHLookOverridePos/* / mDataBlock->maxLookAngle*/, 6);

      headVLookOverridePos = stream->readSignedFloat(6)/* * mDataBlock->maxLookAngle*/;
      headHLookOverridePos = stream->readSignedFloat(6)/* * mDataBlock->maxLookAngle*/;
I'm debating some other possible ideas, so I tend to comment various methods in/out. Clean up as desired.

Thats it for code. If you've set the lookoverride on your mobs (as the player is in the AFX demo), you can now control the head thread's position.
I played around with trying to use Plastic Gems awesome ease code, but it didn't do what I'd hoped. Perhaps because the head threads tend to be just 2 keys? Instead, I opted for a simple schedule setup.
You could easily use the get methods before adjusting, but I didn't really see the point in any more complexity. This looks good.

I used AIGuard, but anything should work...
AIGuard.cs
// This will only work if setLookAnimationOverride is true
function AIGuard::LookDirection(%this, %dir, %a, %r)
{
   %angle = %rotation = -1;
   switch$ (%dir)
   {
      case "down":
         %angle = 0;
         if (%a $= "") %a = %angle;
         %a = %a + 0.1;
      case "up":
         %angle = 1;
         if (%a $= "") %a = %angle;
         %a = %a - 0.1;         
      case "right":
         %rotation = 0;
         if (%r $= "") %r = %rotation;
         %r = %r + 0.1;         
      case "left":
         %rotation = 1;
         if (%r $= "") %r = %rotation;
         %r = %r - 0.1;
      default:
         // 0 them out, then return
         %this.setHeadRotation(0.5);
         %this.setHeadAngle(0.5);
         %rotation = -1;
         %angle = -1;        
   }
     
   // are we done with either/or/both directions?   
   if ((%a >= 1 || %a <= 0) && (%r >= 1 || %r <= 0))
      return;
   
   // we should need one of the two at this point 
   if (%r >= 0)   
      %this.setHeadRotation(%r);  
   if (%a >= 0)      
      %this.setHeadAngle(%a);
   
   // let's do the time warp again...
   %this.schedule(100, "LookDirection", %dir, %a, %r);
}

Sprinkle throughout your scanning routines. AIGuard already has an fov, perhaps anytime it's expanded the mob does a look see?
Some incredible control can be had if you string multiple calls together with a timer here and there, through the task system. I highly recommend getting one of the 3D-Diggers animals (they're cheap!) for some serious indepth look at just how powerful the task system can be.

You only call this with the direction, the other variables are added as needed.
MobIDNum.lookdirection("left"); // left, right, up, down
MobIDNum.lookdirection(); // to revert back...

#1
07/28/2008 (7:13 pm)
Sweet Mary Brown... this is some goodness right here Fafhrd :)
#2
07/30/2008 (3:37 pm)
Sexy, very sexy!
#3
07/30/2008 (7:15 pm)
O.O I've been thinking about doing this, never got around to it though. Mind if I stick some calls to this in my Aiming Resource?


Awesome, thanks!
#4
07/31/2008 (2:39 am)
@Nathan Sure, I stuck your calls in my code :) Aiming does need an additional sanity check or two though... I've found a few cases where it could crash because it couldn't find what it expected.
#5
08/01/2008 (10:55 am)
I've been thinking about trying this for some time now...this is really going to help!
#6
08/07/2008 (7:54 am)
I think it's nice... really
#7
08/22/2008 (6:31 pm)
Plugged it in and it's working great. Nice resource!