Game Development Community

dev|Pro Game Development Curriculum

Splitting Left and Right Strafe Animations

by David Dougher · 04/29/2002 (11:45 am) · 13 comments

In player.h at around line 134 change this routine...

enum {
// *** WARNING ***
// These enum values are used to index the ActionAnimationList
// array instantiated in player.cc
// The first five are selected in the move state based on velocity
RootAnim,
RunForwardAnim,
BackBackwardAnim,
SideLeftAnim,

// These are set explicitly based on player actions
FallAnim,
JumpAnim,
StandJumpAnim,
LandAnim,

//
NumMoveActionAnims = SideLeftAnim + 1,
NumTableActionAnims = LandAnim + 1,
NumExtraActionAnims = 60,
NumActionAnims = NumTableActionAnims + NumExtraActionAnims,
ActionAnimBits = 8,
NullAnimation = (1 << ActionAnimBits) - 1
};

To this routine...

enum {
// *** WARNING ***
// These enum values are used to index the ActionAnimationList
// array instantiated in player.cc
// The first five are selected in the move state based on velocity
RootAnim,
RunForwardAnim,
BackBackwardAnim,
SideLeftAnim,
SideRightAnim, //--dcd--03/15/02

// These are set explicitly based on player actions
FallAnim,
JumpAnim,
StandJumpAnim,
LandAnim,

//
NumMoveActionAnims = SideRightAnim + 1, //--dcd--03/15/02 was SideLeftAnim +1
NumTableActionAnims = LandAnim + 1,
NumExtraActionAnims = 59, //--dcd--03/15/02 was 60
NumActionAnims = NumTableActionAnims + NumExtraActionAnims,
ActionAnimBits = 9, //--dcd--03/15/02 was 8
NullAnimation = (1 << ActionAnimBits) - 1
};

Note that we added the SideRightAnim to complement the SideLeftAnim. We then adjust the NumMoveActionAnims table to point to the new end of those animations. Decrease the number of ExtraActionAnims by one (to keep the table sizes the same as they were) and increase the ActionAnimBits by one to match the new number we have.

Decreasing the number of Extra Animations was probably unnecessary since we do not have 60 extra animations in any model, but it was done in order to make sure that old player characters and new player characters would maintain the size of the data they transfer for performance and debug testing. Later this could be changed back to 60 or altered to the largest number of animations you anticipate.

In player.cc at around line 118-9 change this routine...

// Action Animations:
PlayerData::ActionAnimationDef PlayerData::ActionAnimationList[NumTableActionAnims] =
{
// *** WARNING ***
// This array is indexed useing the enum values defined in player.h

// Root is the default animation
{ "root" }, // RootAnim,

// These are selected in the move state based on velocity
{ "run", { 0,+1,0 } }, // RunForwardAnim,
{ "back", { 0,-1,0 } }, // BackBackwardAnim
{ "side", }, // SideLeftAnim,

// These are set explicitly based on player actions
{ "fall" }, // FallAnim
{ "jump" }, // JumpAnim
{ "standjump" }, // StandJumpAnim
{ "land" }, // LandAnim
};

To this routine...

// Action Animations:
PlayerData::ActionAnimationDef PlayerData::ActionAnimationList[NumTableActionAnims] =
{
// *** WARNING ***
// This array is indexed using the enum values defined in player.h

// Root is the default animation
{ "root" }, // RootAnim,

// These are selected in the move state based on velocity
{ "run", { 0,+1,0 } }, // RunForwardAnim,
{ "back", { 0,-1,0 } }, // BackBackwardAnim
{ "strafeL", { -1,0,0 } }, // SideLeftAnim, --dcd--03/15/02 Note was originally "side"
{ "strafeR", { +1,0,0 } }, // SideRightAnim, --dcd--03/15/02 added { +1, 0, 0} as well

// These are set explicitly based on player actions
{ "fall" }, // FallAnim
{ "jump" }, // JumpAnim
{ "standjump" }, // StandJumpAnim
{ "land" }, // LandAnim
};

The results of this change replace the movement in the old version from “side” to our new “strafeL” and “strafeR”. Also note the addition of the two table entries next to the strafeL and strafeR. These are used by the engine to handle direction along the Y-axis the same way as the “run” and “back” has table entries for movement along the Z-axis.

One could theoretically also create “climb up” and “climb down” or “fly” and “dive” animations by manipulating the last two (x-axis) table entries.

Onward!

In player.cc at around line 2167 change the else clause from...

// 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);
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;
}
}
}

to this (commenting out the special case.)...

// 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);
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
{
//--dcd--03/15/02 Removed this and added directional tables
// for strafeL and strafeR just like forward and backward.

// Special case, re-use slide left animation to slide right
//if (i == PlayerData::SideLeftAnim && -d > curMax) {
// curMax = -d;
// action = i;
// forward = false;
//}
}
}

All we are doing here is commenting out the original code that reversed the animation when a character moved from side to side since we no longer need it. Many people would delete the code but I usually comment it out in order to remember why it was originally in there and to reduce the chance that a CVS update will try and put it back!

That’s it for code changes. The only other change you need to make is to create left and right strafe animations in the datablock for your model and implement the calls in the player.cs file for that model. It looks like this...

datablock TSShapeConstructor(PlayerDts)
{
baseShape = "./player.dts";
sequence0 = "./player_root.dsq root";
sequence1 = "./player_forward.dsq run";
sequence2 = "./player_back.dsq back";
sequence3 = "./player_strafeL.dsq strafeL"; //--dcd--03/15/02
sequence4 = "./player_strafeR.dsq strafeR"; //--dcd--03/15/02
sequence5 = "./player_jump.dsq jump";
sequence6 = "./player_standjump.dsq standjump";
sequence7 = "./player_look.dsq look";
...
}

This is what the strafe left and strafe right animations look like in your player.cs file. There’s nothing special about them. I put them where the original “side” animation was and renumbered the rest of the sequence. The sequence numbers do not appear to be critical since the actions are matched on the basis of the name you gave to the call – in this case strafeL and strafeR – and the animations you are expecting - player_strafeL.dsq and player_strafeR.dsq. However, it is a good idea to place the sequence in the same order as the original call order so you can find things easily, and I believe that the first animation in the sequence must be named “root”.

That’s all there is to it. You can now create your own different animations for strafe running to the left and right. Happy hunting.

About the author

Owner - Pariah Games, Adjunct Professor - Bristol Community College, Mentor - Game Design - Met School Newport, Mentor - Game Design - Met School Providence


#1
04/30/2002 (3:29 pm)
This should go in the Code Snippets, not in the resources...
#2
02/03/2005 (4:22 am)
Got it working easy, way better than having one animation for both ways
Thanks
#3
02/25/2007 (4:44 pm)
I think that this resource dont work in multiplayer.... check this resocurce:
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=4348

in these resource was modificated the packUpdate and unpackUpdate functions...

this need to be updated?
#4
02/26/2007 (6:09 am)
@ Acehart - modifications to pack and unpack functions are not required to make this work. This uses a bit masking operation that is already in the code to set the direction and choose the animation.

You will need to add animations to move left and right that replace the standard side animation. Note that regular characters like the orc will stop moving and slide along the ground because their models have a "side" animation instead of strafeL and strafeR. As soon as you add new dsq's for strafeL and strafeR it will work properly agian.
#7
06/19/2007 (4:26 pm)
This is a fairly old resource since when I created it. I would check to make sure that none of the hardcoded numbers I had you replace have altered since when I created it. However, there is no connection in this code to tranparency.

If you have been adding other resources similar to this one you may have exceeded some limits that exist in the engine. THAT could cause issues such as transparency problems.

It would also be useful to know what veriosn of the engine you are currently working with and whether it has AFX support or not.
#8
07/19/2007 (5:52 am)
it is interesting to see updated version of this for TGE 1.5.2
#9
01/14/2008 (6:10 pm)
I tried it with TGEA 1.0.3 but only right side strafe animation does not work. (no animation on that case)

The changes of the above code seems to be reasonable, traced with break point any supecious lines but no clues.

I renamed 'play_side.dsq' to one for 'play_strafeL.dsq' and the other for 'play_strafeR.dsq' for left and right animations.

Any suggestions?
#10
05/01/2008 (9:25 am)
Got this working fine in TGE 1.5.2 Handy resource. Thanks!
#11
08/06/2008 (5:20 am)
Quote:I renamed 'play_side.dsq' to one for 'play_strafeL.dsq' and the other for 'play_strafeR.dsq' for left and right animations.
I had the same problem - I reused the existing strafe animation. However, I think that these animations are exported with ground transform - so the DSQ file tells Torque "I'm an animation where you move left". Therefore, it never gets picked when you're moving right. You need to make your own animation.

Great resource :)
#12
11/06/2009 (7:48 pm)
In player.cc at around line 2167 change the else clause from...

// 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);
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;
}
}
}

Doesn't exist in T3D any more. What can we do so that we can still implement this?
#13
11/06/2009 (9:14 pm)
I'm always amazed at the life this old resource has.

I haven't looked at the strafe animations in T3D yet so I have no idea how the fix would be implemented. I'll take a look, but I suspect someone with more familiarity with T3D will probably beat me to it.