Effects/SnipeShip.cs
using Sandbox.Utility;
namespace PlanetMeat;
[Group( "Planet Meat - Effects" ), Title( "Snipe Ship" ), Icon( "flight_land" )]
public sealed class SnipeShip : Component
{
public const float AWAY_HEIGHT = 5000.0f;
private const float FACING_LERP_SPEED = 0.5f;
[RequireComponent] public SnipeZone Zone { get; set; }
[RequireComponent] public DelayedStages Stages { get; set; }
[Property] public GameObject ShipAnchor { get; set; }
[Property] public GameObject ShipModel { get; set; }
private Vector3 _lerpPositionStart;
private Vector3 _lerpPositionEnd;
private Rotation _lerpAnglesStart;
private Rotation _lerpAnglesEnd;
private bool _lerpEaseOut;
private bool _lerping = false;
private float Facing => Zone.DriftAngle.RadianToDegree();
private Angles FacingAngles => ShipAnchor.WorldRotation.Angles().WithYaw( Facing );
private Vector3 GetApproachPoint( bool arriving )
{
return new Vector3( Vector2.FromDegrees( ShipAnchor.WorldRotation.Angles().yaw ) * AWAY_HEIGHT * 2.0f * (arriving ? -1.0f : 1.0f), AWAY_HEIGHT );
}
private static Rotation GetApproachRotation( bool arriving )
{
return new Angles( 0.0f, 0.0f, 90.0f * (arriving ? 1.0f : -1.0f) );
}
protected override void OnStart()
{
base.OnStart();
Stages.StageStarted += OnStageStarted;
ShipAnchor.WorldRotation = FacingAngles;
_lerpPositionStart = GetApproachPoint( true );
_lerpPositionEnd = Vector3.Zero;
_lerpAnglesStart = GetApproachRotation( true );
_lerpAnglesEnd = Rotation.Identity;
StartLerp( true );
}
private void StartLerp( bool easeOut )
{
_lerpEaseOut = easeOut;
_lerping = true;
Lerp( 0.0f );
}
protected override void OnUpdate()
{
base.OnUpdate();
if ( _lerping )
Lerp( Stages.Fraction );
ShipAnchor.WorldRotation = Rotation.Lerp(
ShipAnchor.WorldRotation,
FacingAngles,
FACING_LERP_SPEED * Time.Delta
);
}
private void Lerp( float frac )
{
var f = float.IsNaN( frac ) ? 0.0f : frac.Clamp( 0.0f, 1.0f );
ShipModel.LocalRotation = _lerpAnglesStart.LerpTo( _lerpAnglesEnd, f );
f = _lerpEaseOut ? Easing.QuadraticOut( f ) : Easing.QuadraticIn( f );
f = float.IsNaN( f ) ? 0.0f : f.Clamp( 0.0f, 1.0f );
ShipAnchor.LocalPosition = _lerpPositionStart.LerpTo( _lerpPositionEnd, f );
if ( frac >= 1.0f )
_lerping = false;
}
public void OnStageStarted( int stage )
{
if ( stage == DelayedStages.STAGE_INDEX_DESTROY )
{
_lerpPositionStart = ShipAnchor.LocalPosition;
_lerpPositionEnd = GetApproachPoint( false );
_lerpAnglesStart = ShipModel.LocalRotation;
_lerpAnglesEnd = GetApproachRotation( false );
StartLerp( false );
}
else
{
_lerping = false;
}
}
}