Code/Demos/AnimationShowcase/Sections/DampersSection.cs
using System;
using Goo;
using Goo.Animation;
using Sandbox.UI;
using static Sandbox.DemoTokens;
namespace Sandbox.AnimationShowcase;
public class DampersSection
{
const float TrackW = 480f;
const float TrackH = 96f;
const float DotSize = 22f;
const float DotTravel = TrackW - DotSize;
SmoothFloat _smooth = new( initial: 0f, smoothTime: 0.35f );
DecayFloat _decay = new( initial: 0f, halflife: 0.18f );
SpringFloat _spring = new( initial: 0f, frequency: 9f, damping: 0.35f );
public void Update( float dt )
{
_smooth.Update( dt );
_decay.Update( dt );
_spring.Update( dt );
}
public Container Build() => Section.Build(
"dampers - click track to retarget",
new Container
{
FlexDirection = FlexDirection.Row,
Gap = Space4,
AlignItems = Align.FlexStart,
Children =
{
Track(),
Legend.Build(
( "SmoothFloat", "velocity tracked", Accent ),
( "DecayFloat", "exponential, no overshoot", AccentGreen ),
( "SpringFloat", "oscillates", AccentOrange )
),
},
} );
Container Track()
{
var track = new Container
{
Width = TrackW,
Height = TrackH,
BackgroundColor = BgCard,
BorderRadius = Radius2,
Position = PositionMode.Relative,
PointerEvents = PointerEvents.All,
// LocalPosition is rendered-pixel; normalize via Box.Rect into authored coords.
OnClick = e =>
{
float rectW = e.Target?.Box.Rect.Width ?? 0f;
if ( rectW <= 0f ) return;
float frac = Math.Clamp( e.LocalPosition.x / rectW, 0f, 1f );
Retarget( frac * DotTravel );
},
};
track.Children.Add( Dot.AtCorner( _smooth.Current, LaneTop( 0 ), DotSize, Accent ) );
track.Children.Add( Dot.AtCorner( _decay.Current, LaneTop( 1 ), DotSize, AccentGreen ) );
track.Children.Add( Dot.AtCorner( _spring.Current, LaneTop( 2 ), DotSize, AccentOrange ) );
return track;
}
static float LaneTop( int i ) => 14f + i * 24f;
void Retarget( float left )
{
_smooth.Target = left;
_decay.Target = left;
_spring.Target = left;
}
}