-
Notifications
You must be signed in to change notification settings - Fork 3
Particle Pursuit
The explosion of particles that seek a point is probably the coolest effect in the game and was also one of the trickiest to implement.
RELEVANT CODE AT BOTTOM
The first thing to note is that the player actually has two different particle effects. One for regular emission and another for the explosions. Splitting up the two particle behaviors became necessary when I needed to control the explosion without affecting the regular emission as well as give the explosion particles a greater speed and altered noise function. Both particle systems are simulated in World Space.
The regular emission is as simple as calling Play and Stop on the ParticleSystem when the mouse is being clicked. These particles are emitted from a circle at a random angle and collide with the player; this causes the subtle effect of the player pushing particles out of the way. The particles also fade in and out slightly and have a small noise function. All this is controlled in the inspector through the ParticleSystem Component
Identical to the Regular Emission but with a greater initial speed and a much stronger noise function. Emission and movement are controlled almost entirely through a script.
ParticleSystem part;
Reference to the ParticleSystem Component
ParticleSystem.Particle[] particles;
Array of all the particles being controlled. Assigned to an empty array with length part.main.maxParticles in Awake().
int sentParticles
Keeps track of how many particles still need to reach the target
bool sending;
True when the particles are being sent to the target
Vector2 target
current world space position of the target
bool moving
True when the target is a moving target
Transform stillTarget
Target Transform when moving == false
MovingObject movingTarget
(Contains move velocity information) Target MovingObject when moving == true
There are two versions of the SendParticlesTo method:
void SendParticlesTo(Transform target, int minNum)
and void SendParticlesTo(MovingObject target, int minNum)
The first Transform version sets moving = false
the stillTarget while the second MovingObject version sets moving = false
and the movingTarget.
They both set sending = true
, increase sentParticles += minNum * particleMultiplier;
, and emit particles part.Emit(minNum * particleMultiplier);
Note: Use of access modifiers was due to external and inheriting classes. Some irrelevant code was also left out.
[SerializeField] private float particleSpeed;
private const int particleMultiplier = 3;
private const float overshoot = 0.75f;
private const float slowRadius = 6;
protected ParticleSystem part; //ref to this objects particle system
protected ParticleSystemRenderer partRend;
protected ParticleSystem.Particle[] particles; //array of particles being controlled
protected int sentParticles;
protected bool sending; //true when particles arde being sent to a location
protected Vector2 target;
private bool moving = false;
protected Transform stillTarget;
private MovingObject movingTarget;
protected virtual void Awake()
{
part = GetComponent<ParticleSystem>();
particles = new ParticleSystem.Particle[part.main.maxParticles];
part.Stop();
}
/// <summary>
/// Send Particles to a specified world positions
/// </summary>
/// <param name="target">target transform</param>
/// <param name="minNum">minimum number of particles</param>
public void SendParticlesTo(Transform target, int minNum)
{
stillTarget = target;
moving = false;
//emit additional particles
part.Emit(minNum * particleMultiplier);
sentParticles += minNum * particleMultiplier;
//start sending particles to point
sending = true;
}
/// <summary>
/// Send Particles to a specified world positions
/// </summary>
/// <param name="targets">target moving object</param>
/// <param name="minNum">minimum number of particles</param>
public void SendParticlesTo(MovingObject target, int minNum)
{
movingTarget = target;
moving = true;
//emit additional particles
part.Emit(minNum * particleMultiplier);
sentParticles += minNum * particleMultiplier;
//start sending particles to point
sending = true;
}
protected void MoveParticles()
{
if (sending)
{
if (part.isPaused) { part.Play(); }
//loop through all particles
int numParticles = part.GetParticles(particles);
target = moving ? (movingTarget.transform.position + (Vector3)movingTarget.MoveVelocity) : stillTarget.position;
for (int i = 0; i < numParticles; i++)
{
ParticleSystem.Particle particle = particles[i];
//particle.remainingLifetime += Time.deltaTime; //keep particle alive
Vector3 moveVector = ((Vector3)target - particle.position);
moveVector += moveVector.normalized * overshoot;
particle.velocity += ((moveVector.normalized * particleSpeed) - particle.velocity) * Time.deltaTime;
particle.velocity *= Mathf.Clamp((moveVector.magnitude + slowRadius) / 10 , slowRadius * 0.1f , 1);
if (moveVector.magnitude - overshoot < 1f)
{
particle.remainingLifetime = 0;
particle.velocity = Vector3.zero;
sentParticles -= 1;
}
particles[i] = particle; //set the particle's data back into particles array
}
if (sentParticles <= 0 || numParticles <= 0)
{
sentParticles = 0;
sending = false;
part.Stop();
}
part.SetParticles(particles, numParticles); //apply changes to particle system
}
}
Check out a Free Demo of the game on my personal website. (Updated Frequently)