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.