Game Development Community

Player Stand and Turn Animation

by Jeremy Alessi · 05/14/2007 (3:05 pm) · 13 comments

In player.cc find these comments and code:

// Our feet are on something
      // Pick animation that is the best fit for our current velocity.
      // Assumes that root is the first animation in the list.
      F32 curMax = 0.1;
      VectorF vel;
      mWorldToObj.mulV(mVelocity,&vel);

The code beneath the lines listed above selects animations from ActionAnimationList using the following enum values and this selection is velocity dependent.

RootAnim,
      RunForwardAnim,
      BackBackwardAnim,
      SideLeftAnim,

There are other animations which are player action independent such and jumping, falling, and landing and turning could be incorporated that way, but a far more simple method is to use a players delta.rotVec.z which is already present in the network and then add a new condition inside the "Our feet are on something" condition which checks the player's x and y velocity as well as their z rotation before it checks for any of the velocity dependent animations listed in the enum.

If the player is standing still and turning then the side step animation is used (played forward or backward depending on delta.rotVec.z). If the player is moving in anyway then the old code takes precedence.

Replace that code (as seen below):

for (U32 i = 1; i < PlayerData::NumMoveActionAnims; i++)
      {
         PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
         if (anim.sequence != -1 && anim.speed) 
	 {
            F32 d = mDot(vel, anim.dir);
            if (d > curMax)
            {
               curMax = d;
	       action = i;
               forward = true;
            }
            else
            {
               // Special case, re-use slide left animation to slide right
               if (i == PlayerData::SideLeftAnim && -d > curMax )
              {
                  curMax = -d;
                  action = i;
                  forward = false;
              }
	   }
      }

... With this code!

// Stand and Turn animation ... Jeremy's Mods
      // If we're not moving (or just barely due to slope) but our feet are on something
      if ( mFabs( vel.x + vel.y ) < 0.25 )
      {
         // And we're turning
         if ( delta.rotVec.z != 0 )
         {		    

           // Let's sidestep to look like we're turning
	   action = PlayerData::SideLeftAnim; 
           forward = true;

           // If we're turning right animate the other way
	   if ( delta.rotVec.z < 0 ) 
	      forward = false;
         }
      }
      else // Continue on as normal if we're moving
      {
         for (U32 i = 1; i < PlayerData::NumMoveActionAnims; i++)
         {
            PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
            if (anim.sequence != -1 && anim.speed) 
            {
               F32 d = mDot(vel, anim.dir);
               if (d > curMax)
               {
                  curMax = d;
                  action = i;
                  forward = true;
               }
               else
               {
                  // Special case, re-use slide left animation to slide right
                  if (i == PlayerData::SideLeftAnim && -d > curMax )
                  {
                     curMax = -d;
                     action = i;
                     forward = false;
                  }
               }
            }
	 }
      }

The other important factor in this whole operation is that the animation changes dynamically depending on how fast we're turning.

Up just a few lines (~50 or so) this code lies:

// Update action animation time scale to match ground velocity
      PlayerData::ActionAnimation &anim =
         mDataBlock->actionList[mActionAnimation.action];
      F32 scale = 1;
      if (anim.velocityScale && anim.speed)

The next step is to make provisions for z turn speed.

Change the conditional:
if (anim.velocityScale && anim.speed)

to ...

// Jeremy's mods check our delta rotation vector z component
      if (anim.velocityScale && anim.speed || ( delta.rotVec.z != 0 && anim.speed ) )

Also below this:

VectorF vel;
      mWorldToObj.mulV(mVelocity,&vel);
      scale = mFabs(mDot(vel, anim.dir) / anim.speed);

Add this:

// Jeremy's Mods ... add in a turn speed anim scale
      scale = scale + mFabs(20 * ( delta.rotVec.z ));

And ... I think that about does it ... if you strip away all the comments I made it comes down to about 10 lines of code which makes this magical improvement ... why it wasn't there to begin with ... I don't know! I searched for another solution earlier and didn't see one, although I did see questions about it like this:

http://www.garagegames.com/mg/forums/result.thread.php?qt=32671

Hopefully, everyone finds this change useful.

#1
05/14/2007 (5:38 pm)
sweet.
#2
05/14/2007 (6:59 pm)
Very nice! Thanks for sharing:)
#3
05/15/2007 (3:22 pm)
clean, simple and perfect!
#4
05/22/2007 (3:43 pm)
Well done.
#5
05/28/2007 (12:59 pm)
So, what is the name of the animation we should export the DSQ with?
#6
06/15/2007 (6:54 pm)
Brilliant way of handling the situation without creating any extra animations.

Excellent work Jeremy, thank you for the resource! :))
#7
09/10/2007 (6:45 pm)
awesome, great job!

it's funny though but has anyone noticed the footprint donuts you can make by spinning in a circle hehe
#8
10/15/2007 (1:06 pm)
Awesome, thanks so much! Woks like a charm, too, and I think I can figure out how to get a custom animation in there.
Dizzy: Look up PlayerData::SideLeftAnim, and implement something similar, but for your own special animation.
Ben: hah, very cute!
#9
10/24/2008 (11:58 pm)
I'm getting loads of compile errors with TGE 1.5.2.
#10
03/04/2009 (3:29 pm)
Anyone try this in TGEA 1.8.1 ?
#11
03/04/2009 (11:47 pm)
@Tek0
Works as-is in TGEA 1.8.1.
#12
03/11/2009 (2:42 am)
Cool, thanks for the heads up.
#13
04/23/2010 (6:00 am)
Still works in T3D. :)