SILO27: CRASHLANDED Nice Dice Roller: friendly & customizable design OTHER BLOG POSTS

Trails with no gaps for fast moving objects

Cover image

This could be useful to read after the last tutorial: Using Particle Systems with ECS in Unity

The problem

There are many situations where it’s better to control emission of particles by distance travelled instead of time. This is particularly useful if the emitter’s speed varies a lot or it moves too fast so that even emitting every single frame will produce a trail with gaps.

An easy way to solve this is by setting the Rate over Distance instead of Rate over Time field in the ParticleSystem’s inspector.
But that requires duplicating a ParticleSystem for each single one of the objects that you need to emit particles from. Depending on how many you have, this could use up a lot of RAM! And if the effect is the exact same for all of them sometimes it’s just better to reuse the ParticleSystem.
In that case however we no longer can make use of the Rate over Distance since we will be spawning particles manually!

The solution

A good way to do this is to calculate the distance travelled since the previous frame. Then continue to sum these up until it reaches a certain threshold, then emit a particle at that position and reset the distance to let it build up again.

However computing vector distance every frame seems a bit too wasteful, even worse it you have a lot of emitters. And on top of that it doesn’t really solve the problem if the emitter is moving very fast.
Thankfully we can just do it on intervals. Like every half a second or something like that and it behaves almost the same. The solution is then to do it on intervals, every now and then calculate how much you travelled and spawn the backlog of particles accordingly.

emissionTimer += deltaTime;
if (emissionTimer >= emissInterval)
{
    emissionTimer = 0;

    // do emission here
}

The only issue is that there’ll be a little gap between the emitter and the trail (as seen in the screenshot below).

To reduce this gap you can adjust the time interval at which the distance gets calculated. Less time means smaller gap but more performance cost. The best settings depend a lot on your situation, for example at what speed your emitters are travelling.

Personally I just left as it was since they move so fast away from the player that you couldn’t see the gap even if was larger.

Actually emitting

The first step it to compute how much distance we moved since the last time we emitted particles. We then also save the current position in a variable to be used next time.

float travelledDistance = (currentPos - posAtLastEmiss).magnitude;

// after emitting the particles
// set the position to be used next time
posAtLastEmiss = currentPos;

Note that the posAtLastEmiss variable should be initialized to the current emitter position before beginning to emit particles. Otherwise the first time it emits it will think it moved from position 0,0,0 and it’ll create a trail all across your scene!

The next step is to calculate how many particles should be created based on the distance we just computed.

int count = Mathf.RoundToInt(travelledDistance / distanceBetweenParticles);

We now know how many particles we should emit. We can do a loop and compute all the positions simply by using linear interpolation: Vector3.Lerp.

for (int i = 0; i < count; i++)
{
    Vector3 pos = Vector3.Lerp(posAtLastEmiss, currentPos, ((float)i / (float)count));

    // emit the particles with your preferred method
    EmitParticleAtPosition(pos);
}

You can now emit the particle using your preferred method like ParticleSystem.EmitParams. You can find some information on how to use that API in this other tutorial I made: Using Particle Systems with ECS in Unity.

Download files

The Standard package contains the script for the moving emitter. The Premium package, instead, also contains an example scene that shows how to setup the whole thing.

Preview of the example scene

Enjoying the tutorials? Are they useful? Want more?

If you think these posts have either helped or inspired you, please consider supporting this blog.

Help this blog continue existing

If the knowledge you have gained had a significant impact on your project, a mention in the credits would be very appreciated.

Silo27 Logo
Enrico Monese

All around developer, from games and web to weird commandline utilities. 2D/3D art, with a good care for UI/UX and clean design.

Twitter Twitter Patreon Patreon Mastodon Mastodon Blog Blog   Reddit Reddit Github Github Gitlab Gitlab ArtStation ArtStation Instagram Instagram Mail Mail