A component that represents a thrown chain hook. It updates its position and rotation relative to an AnchorUnit, renders a line between the anchor and hook, times out after Lifetime, and attaches to players that enter its trigger to apply a Chain effect.
using System;
using Sandbox;
public class ChainHook : Component, Component.ITriggerListener
{
[Property] public LineRenderer LineRenderer { get; set; }
[Sync] public Unit AnchorUnit { get; set; }
public Vector2 Direction { get; set; }
public float Distance { get; set; }
private TimeSince _timeSinceSpawn;
public float Lifetime { get; set; }
protected override void OnAwake()
{
base.OnAwake();
_timeSinceSpawn = 0f;
}
protected override void OnUpdate()
{
base.OnUpdate();
//Gizmo.Draw.Color = Color.White;
//Gizmo.Draw.Text( $"AnchorUnit: {AnchorUnit}", new global::Transform( WorldPosition ) );
if ( !AnchorUnit.IsValid() || AnchorUnit.IsDying )
{
GameObject.Destroy();
return;
}
if ( AnchorUnit.IsValid() )
LineRenderer.VectorPoints[0] = AnchorUnit.WorldPosition + new Vector3( 0f, 0f, AnchorUnit.Height * 0.75f );
LineRenderer.VectorPoints[1] = WorldPosition;
if ( IsProxy )
return;
var anchorPos = AnchorUnit.WorldPosition.WithZ( 50f );
WorldPosition = anchorPos + (Vector3)Direction * Distance * Utils.MapReturn( _timeSinceSpawn, 0f, Lifetime, 0f, 1f, EasingType.SineOut );
WorldRotation = Rotation.From( 0f, -Utils.GetAngleDegreesFromVector( (WorldPosition - anchorPos).Normal ), 0f );
if ( _timeSinceSpawn > Lifetime )
GameObject.Destroy();
}
void ITriggerListener.OnTriggerEnter( Collider collider )
{
if ( IsProxy || !collider.IsTrigger )
return;
var thing = collider.GetComponent<Thing>();
if ( !thing.IsValid() )
return;
if ( !thing.Tags.HasAny( "player") )
return;
var player = thing as Player;
if ( !player.IsValid() )
return;
if ( player.IsInvincible )
return;
var chainLifetime = Utils.Select( Manager.Instance.Difficulty, 6f, 10f, 12f );
player.Chain( AnchorUnit, AnchorUnit.WorldPosition, chainLength: 150f, lifetime: chainLifetime );
GameObject.Destroy();
}
}