WorkInProgress/ParticleLineEmitter.cs
namespace Sandbox;
/// <summary>
/// Emits particles in a line. The line can be flat or have a tube-like quality.
/// </summary>
[Title( "Line Emitter" )]
[Category( "Particles" )]
[Icon( "stacked_line_chart" )]
public sealed class ParticleLineEmitter : ParticleEmitter
{
[Group( "Line" )]
[Property] public Vector3 TargetPosition { get; set; } = new Vector3( 500, 0, 0 );
[Group( "Line" )]
[Property] public ParticleFloat Thickness { get; set; } = 0.0f;
[Group( "Placement" )]
[Property] public float MinDistance { get; set; } = 0.0f;
[Group( "Placement" )]
[Property]
public bool PlaceRandomly { get; set; }
[Group( "Placement" )]
[Property]
public bool PlaceAdvanced { get; set; }
[ShowIf( "PlaceAdvanced", true )]
[Group( "Placement" )]
[Property]
public ParticleFloat EmitLinePosition { get; set; } = new ParticleFloat { Type = ParticleFloat.ValueType.Range, Evaluation = ParticleFloat.EvaluationType.Life, ConstantA = 0, ConstantB = 1 };
[Group( "Velocity" )][Property] public bool ApplyVelocity { get; set; }
[ShowIf( "ApplyVelocity", true )][Group( "Velocity" )][Property] public bool ScaleByDistance { get; set; }
[ShowIf( "ScaleByDistance", true )][Group( "Velocity" )][Property] public ParticleFloat FixedVelocity { get; set; } = 100.0f;
[ShowIf( "ApplyVelocity", true )][Group( "Velocity" )][Property] public float VelocityRandom { get; set; }
protected override void DrawGizmos()
{
base.DrawGizmos();
if ( Gizmo.IsSelected )
{
Gizmo.Draw.Color = Color.White.WithAlpha( 0.05f );
Gizmo.Draw.Line( 0, TargetPosition );
var pos = WorldTransform.PointToWorld( TargetPosition );
using ( Gizmo.Scope( "Tool", new Transform( TargetPosition ) ) )
{
if ( Gizmo.Control.Position( "TargetPosition", 0, out var newPos ) )
{
TargetPosition += newPos;
}
}
}
}
protected override int GetBurstCount()
{
var count = base.GetBurstCount();
if ( count <= 0 ) return 0;
Vector3 from = WorldTransform.Position;
Vector3 to = WorldTransform.PointToWorld( TargetPosition );
var moveDelta = (to - from).Length;
var minDistance = MinDistance;
if ( minDistance > 0.5f )
{
int minCount = (int)(moveDelta / minDistance);
if ( count < minCount ) count = minCount;
}
return count;
}
protected override int GetRateCount()
{
var count = base.GetRateCount();
if ( count <= 0 ) return 0;
Vector3 from = WorldPosition;
Vector3 to = WorldTransform.PointToWorld( TargetPosition );
var moveDelta = (to - from).Length;
var minDistance = MinDistance;
if ( minDistance > 0.5f )
{
int minCount = (int)(moveDelta / minDistance);
if ( count < minCount ) count = minCount;
}
return count;
}
public override bool Emit( ParticleEffect target )
{
Vector3 from = WorldPosition;
Vector3 to = WorldTransform.PointToWorld( TargetPosition );
var moveDelta = to - from;
var lineNormal = moveDelta.Normal;
var delta = Delta;
if ( PlaceRandomly )
{
delta = Random.Shared.Float( 0, 1 );
}
else if ( PlaceAdvanced )
{
delta = EmitLinePosition.Evaluate( delta, Random.Shared.Float( 0, 1 ) );
}
var pos = from.LerpTo( to, delta );
float thickness = Thickness.Evaluate( Delta, 63456 );
if ( thickness != 0.0f )
{
pos += Vector3.Random.SubtractDirection( lineNormal ) * thickness;
}
var p = target.Emit( pos, Random.Shared.Float( 0, 1 ) );
if ( p is not null )
{
if ( ApplyVelocity )
{
p.Position = from;
var velocity = (to - from) / p.LifeTimeRemaining;
p.Velocity = velocity;
p.Velocity += VelocityRandom * Vector3.Random;
if ( ScaleByDistance )
{
p.TimeScale = FixedVelocity.Evaluate( Delta, 1336 ) / moveDelta.Length;
}
}
}
return true;
}
}