Stop collision detection on particles

I have a particle system emitting particles that are falling onto the ground. Dampen is 1 and bounce is 0, so they stick to the ground, which causes a performance issue since the system keeps detecting collisions between these particles and the ground.

I thought I could remove the particles from this system and add them to another system which would have collision detection turned off, but I don’t know if it’s possible.

So far, my code (which can be enhanced for performance later) finds the particles that collided and remove them from the particle system. How can I transfer them to another system or achieve what I want some other way?

using UnityEngine;
using System.Collections;

using Particle = UnityEngine.ParticleSystem.Particle;

public class ParticleStopper : MonoBehaviour {

    ParticleSystem particleSystem;

    void Start ()
    {
        particleSystem = GetComponent<ParticleSystem>();
    }
   
    void OnParticleCollision(GameObject other)
    {
        Particle[] particles = new Particle[particleSystem.maxParticles];
        int nParticles = particleSystem.GetParticles(particles);

        ParticleCollisionEvent[] collisions = new ParticleCollisionEvent[particleSystem.GetSafeCollisionEventSize()];
        int nCollisions = particleSystem.GetCollisionEvents(other, collisions);

        if (nCollisions > nParticles) // not really sure why this happens sometimes
            return;

        for(int j = 0; j < nCollisions; j++)
        {
            Vector3 collisionLocation = collisions[j].intersection;
            float closest = float.MaxValue;
            int closestIndex = -1;
            for(int i = 0; i < nParticles; i++)
            {
                float distance = (particles[i].position - collisionLocation).sqrMagnitude;
                if(distance < closest)
                {
                    closest = distance;
                    closestIndex = i;
                }           
            }

            particles = particles.RemoveAt(closestIndex, nParticles);
            nParticles--;
        }

        particleSystem.SetParticles(particles, nParticles);
    }
}

public static class ParticleExtensions {

    public static Particle[] RemoveAt(this Particle[] source, int index, int length)
    {
        if (length == 0)
            return new Particle[0];
       
        Particle[] dest = new Particle[length - 1];
        if( index > 0 )
            System.Array.Copy(source, 0, dest, 0, index);

        if( index < source.Length - 1 )
            System.Array.Copy(source, index + 1, dest, index, length - index - 1);

        return dest;
    }
}

Thanks

havent used particle collision scripts much,
but if you set lifetimeloss to 1, so that they die on collision, i think still get their collision point first?

so then can just spawn mesh decal or move other particle system particle on that position…
either by moving particles manually, or moving the whole particle system on that position and emitting 1 particle there…

1 Like

Thank you.

I tried creating a sprite mesh decal but I’m using the Texture Sheet Animation module in the particle system and I don’t know how to read/predict which sprite tile is being used in a particular particle.
It’s a shame because I was able to read everything else so the solution looks good except for this.

I don’t think having a second particle system would work because of the same reason, also I don’t think I would be able to set other things too (size, colour…)

It turned out I indeed can “transfer” particles from one particle system to another and make them look exactly the same, even when using Texture Sheet Animation.

I cloned the particle system using Instantiate(sourceSystem), and then playing with sourceSystem.GetParticles and clonedSystem.SetParticles I can recreate the particles in the cloned system.

The performance was great.

2 Likes

Nice trick! I will remember that one.