AI/Agents/Agent.Animation.cs
namespace HC3;
public partial class Agent
{
/// <summary>
/// The skinned model renderer for this agent.
/// </summary>
[Property, Feature( "Animation" )] public SkinnedModelRenderer Body { get; set; }
/// <summary>
/// Synced property to determine if the agent is moving.
/// </summary>
[Sync( SyncFlags.FromHost )] public bool IsMoving { get; set; }
/// <summary>
/// The run sequence to use
/// </summary>
[Property, Feature( "Animation" )] public string RunSequence { get; set; } = "Run_01";
/// <summary>
/// The walk sequence to use
/// </summary>
[Property, Feature( "Animation" )] public string WalkSequence { get; set; } = "Walk_01";
/// <summary>
/// Scale move speed by this factor to avoid skating
/// </summary>
[Property, Feature( "Animation" )] public float SkatingMultiplier { get; set; } = 1.5f;
/// <summary>
/// A list of idle sequences to use
/// </summary>
[Property, Feature( "Animation" )]
public List<string> IdleSequences { get; set; } = new()
{
"IdlePose_01",
"IdlePose_02",
"IdlePose_03",
"IdlePose_04",
"IdlePose_05"
};
protected TimeSince _timeSinceIdle = 999;
protected string _sequenceOverride;
protected float _sequenceOverrideSpeed = 1f;
/// <summary>
/// Sets the sequence for the agent.
/// </summary>
/// <param name="sequence"></param>
/// <param name="speed"></param>
protected void SetSequence( string sequence, float speed = 1f )
{
Body.Sequence.PlaybackRate = speed;
// Don't reset if we're already running this
if ( Body.Sequence?.Name?.Equals( sequence ) ?? false )
return;
Body.Sequence.Name = sequence;
}
/// <summary>
/// Sets the sequence override for the agent. This means the agent will always play this sequence, on a loop. Remember to unset.
/// </summary>
/// <param name="sequence"></param>
/// <param name="speed"></param>
public void SetSequenceOverride( string sequence, float speed = 1f )
{
_sequenceOverride = sequence;
_sequenceOverrideSpeed = speed;
}
protected void UpdateIdle()
{
if ( _timeSinceIdle > 5 )
{
SetSequence( Game.Random.FromList( IdleSequences ) );
_timeSinceIdle = 0;
}
}
public virtual float WalkSpeed
{
get
{
// 0.15f because the model is scaled incorrectly
var scale = Body.WorldScale.z / 0.15f;
if ( scale >= 0.8f )
return 1f;
var t = scale.LerpInverse( 0.8f, 0.5f, true );
var val = 1f.LerpTo( 2f, t );
return val;
}
}
protected void UpdateAnimation()
{
if ( !Game.IsPlaying )
return;
if ( Networking.IsHost )
IsMoving = Controller.IsNavigating;
if ( !string.IsNullOrEmpty( _sequenceOverride ) )
{
SetSequence( _sequenceOverride, _sequenceOverrideSpeed );
return;
}
if ( !Controller.IsGrounded )
{
SetSequence( "Flail" );
}
else if ( IsMoving )
{
SetSequence( Controller.IsRunning ? RunSequence : WalkSequence, WalkSpeed * SkatingMultiplier );
}
else
{
UpdateIdle();
}
}
}