A tossed enemy projectile entity. It interpolates a 2D trajectory and an arc height over its Lifetime, updates WorldPosition each tick, and spawns impact particles when it hits the ground or is removed.
using System;
using Sandbox;
public class TossedProjectile : EnemyProjectile
{
[Property] public GameObject Model { get; set; }
[Sync] public float Damage { get; set; }
public float Lifetime { get; set; }
[Sync] public Enemy Shooter { get; set; }
protected float _hitForce;
protected Color _impactParticleColor;
protected float _height;
protected float _startHeight;
public Vector2 StartPos2D { get; set; }
public Vector2 TargetPos2D { get; set; }
protected override void OnStart()
{
base.OnStart();
if ( IsProxy )
return;
_startHeight = WorldPosition.z;
}
protected override void OnUpdate()
{
base.OnUpdate();
if ( IsProxy )
return;
//Gizmo.Draw.Color = Color.White;
//Gizmo.Draw.Text( $"TimeSinceSpawn: {TimeSinceSpawn}\nLifetime: {Lifetime}", new global::Transform( WorldPosition ) );
// todo: move with wind force
Vector2 pos2D = Vector2.Lerp( StartPos2D, TargetPos2D, Utils.Map( TimeSinceSpawn, 0f, Lifetime, 0f, 1f, EasingType.Linear ) );
float zPos = TimeSinceSpawn < Lifetime * 0.5f
? Utils.Map( TimeSinceSpawn, 0f, Lifetime * 0.5f, _startHeight, _height, EasingType.QuadOut )
: Utils.Map( TimeSinceSpawn, Lifetime * 0.5f, Lifetime, _height, 0f, EasingType.QuadIn );
WorldPosition = new Vector3( pos2D.x, pos2D.y, zPos );
if ( TimeSinceSpawn > Lifetime )
{
HitGround();
}
}
protected virtual void HitGround()
{
RemoveRpc( shouldSpawnEffects: true );
}
protected override void Remove( bool shouldSpawnEffects )
{
base.Remove( shouldSpawnEffects );
if( shouldSpawnEffects )
Manager.Instance.SpawnBulletImpactParticles( WorldPosition.WithZ( Math.Max( WorldPosition.z, 10f ) ), Vector3.Up, _impactParticleColor );
if ( IsProxy )
return;
}
}