Revision Difference
Player_Animator#546580
<cat>Code.Player</cat>
<title>Player Animator</title>
# What is a Player Animator
The Animator is responsible for maintaining your AnimGraph with up to date information. You can also set the position and rotation of your player in the Animator.
# Example
```
public class StandardPlayerAnimator : PlayerAnimator⤶
{
public override void Tick()
{⤶
DoRotation();
DoWalk();
//⤶
// Let the animation graph know some shit⤶
//⤶
SetParam( "b_grounded", GroundEntity != null );
//⤶
// Look in the direction what the player's input is facing⤶
//⤶
SetLookAt( "lookat_pos", Player.EyePos + Input.Rot.Forward * 1000 );⤶
}
⤶
public virtual void DoRotation()
{
//⤶
// Our ideal player model rotation is the way we're facing⤶
//⤶
var idealRotation = Rotation.LookAt( Input.Rot.Forward.WithZ( 0 ), Vector3.Up );
//⤶
// If we're moving, rotate to our ideal rotation⤶
//⤶
Rot = Rotation.Slerp( Rot, idealRotation, WishVelocity.Length * Time.Delta * 0.01f );
//⤶
// Clamp the foot rotation to within 120 degrees of the ideal rotation⤶
//⤶
Rot = Rot.Clamp( idealRotation, 120 );⤶
}
⤶
void DoWalk()
{
//⤶
// These tweak the animation speeds to something we feel is right,
// so the foot speed matches the floor speed. Your art should probably⤶
// do this - but that ain't how we roll⤶
//⤶
SetParam( "walkspeed_scale", 2.0f / 190.0f );
SetParam( "runspeed_scale", 2.0f / 320.0f );
⤶
//⤶
// Work out our movement relative to our body rotation⤶
//⤶
var moveDir = WishVelocity.Normal;
var forward = Rot.Forward.Dot( moveDir );
var sideward = Rot.Right.Dot( moveDir );
//⤶
// Set our speeds on the animgraph⤶
//⤶
SetParam( "forward", forward );
SetParam( "sideward", sideward );⤶
SetParam( "wishspeed", WishVelocity.Length );⤶
}
}
public class StandardPlayerAnimator : PawnAnimator⤶
{
TimeSince TimeSinceFootShuffle = 60;
⤶
⤶
float duck;
⤶
public override void Simulate()
{
var player = Pawn as Player;⤶
var idealRotation = Rotation.LookAt( Input.Rotation.Forward.WithZ( 0 ), Vector3.Up );⤶
⤶
DoRotation( idealRotation );
DoWalk();
⤶
//⤶
// Let the animation graph know some shit⤶
//⤶
bool sitting = HasTag( "sitting" );
bool noclip = HasTag( "noclip" ) && !sitting;
⤶
SetAnimParameter( "b_grounded", GroundEntity != null || noclip || sitting );
SetAnimParameter( "b_noclip", noclip );⤶
SetAnimParameter( "b_sit", sitting );⤶
SetAnimParameter( "b_swim", Pawn.WaterLevel > 0.5f && !sitting );⤶
⤶
if ( Host.IsClient && Client.IsValid() )
{
SetAnimParameter( "voice", Client.TimeSinceLastVoice < 0.5f ? Client.VoiceLevel : 0.0f );⤶
}⤶
⤶
Vector3 aimPos = Pawn.EyePosition + Input.Rotation.Forward * 200;
Vector3 lookPos = aimPos;
⤶
//⤶
// Look in the direction what the player's input is facing⤶
//⤶
SetLookAt( "aim_eyes", lookPos );
SetLookAt( "aim_head", lookPos );
SetLookAt( "aim_body", aimPos );
⤶
if ( HasTag( "ducked" ) ) duck = duck.LerpTo( 1.0f, Time.Delta * 10.0f );⤶
else duck = duck.LerpTo( 0.0f, Time.Delta * 5.0f );
⤶
SetAnimParameter( "duck", duck );⤶
⤶
if ( player != null && player.ActiveChild is BaseCarriable carry )⤶
{⤶
carry.SimulateAnimator( this );
}
else⤶
{⤶
SetAnimParameter( "holdtype", 0 );⤶
SetAnimParameter( "aim_body_weight", 0.5f );
}
⤶
}
public virtual void DoRotation( Rotation idealRotation )⤶
{⤶
var player = Pawn as Player;⤶
//⤶
// Our ideal player model rotation is the way we're facing⤶
//⤶
var allowYawDiff = player?.ActiveChild == null ? 90 : 50;
⤶
float turnSpeed = 0.01f;
if ( HasTag( "ducked" ) ) turnSpeed = 0.1f;⤶
⤶
//⤶
// If we're moving, rotate to our ideal rotation⤶
//⤶
Rotation = Rotation.Slerp( Rotation, idealRotation, WishVelocity.Length * Time.Delta * turnSpeed );⤶
⤶
//⤶
// Clamp the foot rotation to within 120 degrees of the ideal rotation⤶
//⤶
Rotation = Rotation.Clamp( idealRotation, allowYawDiff, out var change );⤶
⤶
//⤶
// If we did restrict, and are standing still, add a foot shuffle⤶
//⤶
if ( change > 1 && WishVelocity.Length <= 1 ) TimeSinceFootShuffle = 0;⤶
⤶
SetAnimParameter( "b_shuffle", TimeSinceFootShuffle < 0.1 );⤶
}⤶
⤶
void DoWalk()⤶
{⤶
// Move Speed⤶
{⤶
var dir = Velocity;⤶
var forward = Rotation.Forward.Dot( dir );⤶
var sideward = Rotation.Right.Dot( dir );⤶
⤶
var angle = MathF.Atan2( sideward, forward ).RadianToDegree().NormalizeDegrees();⤶
⤶
SetAnimParameter( "move_direction", angle );⤶
SetAnimParameter( "move_speed", Velocity.Length );⤶
SetAnimParameter( "move_groundspeed", Velocity.WithZ( 0 ).Length );⤶
SetAnimParameter( "move_y", sideward );⤶
SetAnimParameter( "move_x", forward );⤶
SetAnimParameter( "move_z", Velocity.z );⤶
}⤶
⤶
// Wish Speed⤶
{⤶
var dir = WishVelocity;⤶
var forward = Rotation.Forward.Dot( dir );⤶
var sideward = Rotation.Right.Dot( dir );⤶
⤶
var angle = MathF.Atan2( sideward, forward ).RadianToDegree().NormalizeDegrees();⤶
⤶
SetAnimParameter( "wish_direction", angle );⤶
SetAnimParameter( "wish_speed", WishVelocity.Length );⤶
SetAnimParameter( "wish_groundspeed", WishVelocity.WithZ( 0 ).Length );⤶
SetAnimParameter( "wish_y", sideward );⤶
SetAnimParameter( "wish_x", forward );⤶
SetAnimParameter( "wish_z", WishVelocity.z );⤶
}⤶
}⤶
⤶
public override void OnEvent( string name )⤶
{⤶
// DebugOverlay.Text( Pos + Vector3.Up * 100, name, 5.0f );⤶
⤶
if ( name == "jump" )⤶
{⤶
Trigger( "b_jump" );⤶
}⤶
⤶
base.OnEvent( name );⤶
}⤶
}⤶
```
# Setting
Setting the Animator is the same as setting a <page>Player Controller</page>.
```
public override void Respawn()
{
base.Respawn();
Animator = new StandardPlayerAnimator();
}
```
Like the <page>Player Controller</page>, this property can be changed at any time and is replicated to the client. Setting to null will mean your player isn't animated.