Case:
cs
ConfettiCannon.Fire(new ConfettiCannon.Options
{
ParticleCount = 100,
Spread = 70,
Origin = new Point(0.5, 0.6)
});
//OR
var random = new Random();
ConfettiCannon.Fire(new ConfettiCannon.Options
{
Angle = random.Next(55, 125),
Spread = random.Next(50, 70),
ParticleCount = random.Next(50, 100),
Origin = new Point(0.5, 0.6)
});
//Realistic
const int count = 200;
Fire(0.25, new ConfettiCannon.Options { Spread = 26, StartVelocity = 55 });
Fire(0.2, new ConfettiCannon.Options { Spread = 60 });
Fire(0.35, new ConfettiCannon.Options { Spread = 100, Decay = 0.91, Scalar = 0.8 });
Fire(0.1, new ConfettiCannon.Options { Spread = 120, StartVelocity = 25, Decay = 0.92, Scalar = 1.2 });
Fire(0.1, new ConfettiCannon.Options { Spread = 120, StartVelocity = 45 });
return;
void Fire(double particleRatio, ConfettiCannon.Options options)
{
options.ParticleCount = (int) Math.Floor(count * particleRatio);
ConfettiCannon.Fire(options);
}
//Firework
const int duration = 15 * 1000;
var random = new Random();
DateTime animationEnd = DateTime.Now + TimeSpan.FromMilliseconds(duration);
var timer = new DispatcherTimer(DispatcherPriority.ApplicationIdle)
{
Interval = TimeSpan.FromMilliseconds(250)
};
timer.Tick += OnTimerOnTick;
timer.Start();
return;
void OnTimerOnTick(object o, EventArgs _)
{
double timeLeft = (animationEnd - DateTime.Now).TotalMilliseconds;
if (timeLeft <= 0)
{
timer.Tick -= OnTimerOnTick;
timer.Stop();
}
var particleCount = (int) (50 * (timeLeft / duration));
ConfettiCannon.Fire(new ConfettiCannon.Options
{
StartVelocity = 30,
Spread = 360,
Ticks = 60,
ParticleCount = particleCount,
Origin = new Point
{
X = RandomInRange(0.1, 0.3),
Y = random.NextDouble() - 0.2
}
});
ConfettiCannon.Fire(new ConfettiCannon.Options
{
StartVelocity = 30,
Spread = 360,
Ticks = 60,
ParticleCount = particleCount,
Origin = new Point
{
X = RandomInRange(0.7, 0.9),
Y = random.NextDouble() - 0.2
}
});
}
// Starts
SetTimeout(Shoot, 0);
SetTimeout(Shoot, 100);
SetTimeout(Shoot, 200);
return;
void Shoot()
{
ConfettiCannon.Fire(new ConfettiCannon.Options
{
Spread = 360,
Ticks = 50,
Gravity = 0,
Decay = 0.94,
StartVelocity = 30,
Colors = ["#FFE400", "#FFBD00", "#E89400", "#FFCA6C", "#FDFFB8"],
ParticleCount = 40,
Scalar = 1.2,
Shapes = ["star"]
});
ConfettiCannon.Fire(new ConfettiCannon.Options
{
Spread = 360,
Ticks = 50,
Gravity = 0,
Decay = 0.94,
StartVelocity = 30,
Colors = ["#FFE400", "#FFBD00", "#E89400", "#FFCA6C", "#FDFFB8"],
ParticleCount = 10,
Scalar = 0.75,
Shapes = ["circle"]
});
}
void SetTimeout(Action action, int delayMilliseconds)
{
var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(delayMilliseconds) };
timer.Tick += OnTimerOnTick;
timer.Start();
}
void OnTimerOnTick(object o, EventArgs _)
{
Shoot();
if (o is not DispatcherTimer timer)
{
return;
}
timer.Tick -= OnTimerOnTick;
timer.Stop();
}
//Snow
const int duration = 15 * 1000;
var random = new Random();
DateTime animationEnd = DateTime.Now + TimeSpan.FromMilliseconds(duration);
double skew = 1;
new AnimationFrame().Start(_ =>
{
double timeLeft = (animationEnd - DateTime.Now).TotalMilliseconds;
if (timeLeft <= 0)
{
return true;
}
int ticks = (int) Math.Max(200, 500 * (timeLeft / duration));
// ReSharper disable once AccessToModifiedClosure
skew = Math.Max(0.8, skew - 0.001);
ConfettiCannon.Fire(new ConfettiCannon.Options
{
ParticleCount = 1,
StartVelocity = 0,
Ticks = ticks,
Origin = new Point
{
X = random.NextDouble(),
Y = random.NextDouble() * skew - 0.2
},
Colors = ["#ffffff"],
Shapes = ["circle"],
Gravity = RandomInRange(0.4, 0.6),
Scalar = RandomInRange(0.4, 1),
Drift = RandomInRange(-0.4, 0.4),
});
return false;
});
//School Pride
const int duration = 15 * 1000;
DateTime animationEnd = DateTime.Now + TimeSpan.FromMilliseconds(duration);
new AnimationFrame().Start(_ =>
{
double timeLeft = (animationEnd - DateTime.Now).TotalMilliseconds;
if (timeLeft <= 0)
{
return true;
}
ConfettiCannon.Fire(new ConfettiCannon.Options
{
ParticleCount = 2,
Angle = 60,
Spread = 55,
Origin = new Point(0, 0.5),
Colors = ["#bb0000", "#ffffff"],
});
ConfettiCannon.Fire(new ConfettiCannon.Options
{
ParticleCount = 2,
Angle = 120,
Spread = 55,
Origin = new Point(1, 0.5),
Colors = ["#bb0000", "#ffffff"],
});
return false;
});
private static double RandomInRange(double min, double max)
{
var random = new Random();
return random.NextDouble() * (max - min) + min;
}
private class AnimationFrame
{
private Func<double, bool> _callback;
private long _lastTicks;
public void Start(Func<double, bool> callback)
{
_callback = callback;
_lastTicks = DateTime.Now.Ticks;
CompositionTarget.Rendering += OnRendering;
}
private void OnRendering(object sender, EventArgs e)
{
long nowTicks = DateTime.Now.Ticks;
double deltaTime = (nowTicks - _lastTicks) / 10000000.0;
_lastTicks = nowTicks;
if (_callback?.Invoke(deltaTime) == true)
{
CompositionTarget.Rendering -= OnRendering;
}
}
}effect:
