things/LavaSafeSpot.cs

A Thing-derived game object representing a moving "lava safe spot" zone. It controls spawn positioning, lifetime, vertical easing when appearing/disappearing, movement based on MoveDir and Speed, collision response that repels from other things, bounds reflection, and scaling that updates its radius from a SphereCollider.

File AccessNetworking
using System;
using Sandbox;

public class LavaSafeSpot : Thing
{
	[Property] public ModelRenderer ModelRenderer { get; set; }

	//public override Vector3 SpawnScale => new Vector3( 4f, 4f, 1f );
	public override bool UseSpawnScale => false;

	public Vector2 MoveDir { get; set; }

	public override bool BoundsCheckIncludesRadius => true;

	public float Speed { get; set; }
	public virtual float SpawnZPos => -15f;

	public float Lifetime { get; set; }

	protected override void OnStart()
	{
		base.OnStart();

		ShouldCheckBounds = true;

		WorldPosition = WorldPosition.WithZ( SpawnZPos );

		if ( IsProxy )
			return;

		Lifetime = 60f;

		CollideWithTags.Add( "lava_safe_spot" );
	}

	protected override void OnUpdate()
	{
		base.OnUpdate();

		//Gizmo.Draw.Color = Color.White;
		//Gizmo.Draw.Text( $"{Radius}", new global::Transform( WorldPosition ) );

		if ( IsProxy )
			return;

		var spawnTime = 1.5f;
		if(TimeSinceSpawn < spawnTime )
		{
			WorldPosition = WorldPosition.WithZ( Utils.Map( TimeSinceSpawn, 0f, spawnTime, SpawnZPos, 0f ) );
		}
		else if( TimeSinceSpawn > Lifetime - spawnTime )
		{
			WorldPosition = WorldPosition.WithZ( Utils.Map( TimeSinceSpawn, Lifetime - spawnTime, Lifetime, 0f, SpawnZPos ) );
		}

		WorldPosition += (Vector3)MoveDir * Speed * Time.Delta;

		if(TimeSinceSpawn > Lifetime)
		{
			GameObject.Destroy();
		}
	}

	public override void Colliding( Thing other, float percent, float dt )
	{
		base.Colliding( other, percent, dt );

		MoveDir = (Position2D - other.Position2D).Normal;
	}

	protected override void OnOutOfBounds( Direction direction )
	{
		base.OnOutOfBounds( direction );

		if ( direction == Direction.Left )
			MoveDir = new Vector2( Math.Abs( MoveDir.x ), MoveDir.y );
		else if ( direction == Direction.Right )
			MoveDir = new Vector2( -Math.Abs( MoveDir.x ), MoveDir.y );
		else if ( direction == Direction.Down )
			MoveDir = new Vector2( MoveDir.x, Math.Abs( MoveDir.y ) );
		else if ( direction == Direction.Up )
			MoveDir = new Vector2( MoveDir.x, -Math.Abs( MoveDir.y ) );
	}

	public void SetScale(float scale)
	{
		WorldScale = new Vector3( scale, scale, 1f );

		var sphereCollider = Collider as SphereCollider;
		Radius = sphereCollider.Radius * WorldScale.x;
	}
}