Search code examples
c#unity-game-engineparticle-system

Newly spawned particles instantly destroyed after lifespan expires in a custom particle system script


I'm trying to create a particle system script from scratch. The problem is that I want to spawn particles and after a certain lifespan destroy them so it won't keep loading the memory with particles infinitly.

This is the Particle script. I set

using System.Collections.Generic;
using UnityEngine;

public class Particle : MonoBehaviour
{
    public Vector3 position;
    public Vector3 velocity;
    public Vector3 gravityAcceleration = new Vector3(0, -9.81f, 0);
    public float lifespan = 5f;

    void Start()
    {
        velocity = new Vector3(Random.Range(-2f, 2f), Random.Range(-2f, 2f), Random.Range(-2f, 2f));
    }

    // Update is called once per frame
    void Update()
    {
        // Update position and velocity
        velocity += gravityAcceleration*Time.deltaTime;
        transform.position += velocity*Time.deltaTime;

        // Decrease the lifespan of the particle
        lifespan -= Time.deltaTime;
        if (lifespan <= 0f && this.gameObject != null) 
        {
            Destroy(this.gameObject); // Destroy particle when lifespan expires
        }
    } 
}

and this is the emitter script:

using System.Collections.Generic;
using UnityEngine;

public class ParticleEmitter : MonoBehaviour {

    public GameObject particlePrefab; // This creates a reusable GameObsejt asset (prefab) to create and asign particles dynamically while the script runs.
    public float particleRate = 20f; // Particles created per second.
    public float timer = 0f; // Time interval between 2 particle creation cycles.
    //private List<GameObject> particles = new List<GameObject>(); // A list to store all the particles created so I can iterate and update/remove them.


    void CreateParticle() {
        GameObject particle = Instantiate(particlePrefab, transform.position, transform.rotation);
        //particles.Add(particle);
    }

    // Update is called once per frame
    void Update()
    {
        timer += Time.deltaTime;
        
        if(timer >= 1f / particleRate) {
            CreateParticle();   
            timer = 0f;
        }

    }
}

In this example I have set the lifespan at 2 seconds and as you can see after 2 seconds all particles are destroyed, and after that all newly spawned particles are also destroyed instantly. It appears that this lifespan variable is shared between all particles, how can I make it unique for each particle?

example lifespan = 2 sec.


Solution

  • Example:

    Use coroutine to disable/destroy the Particle's gameObject after lifespan.

    Remove from Update:

            lifespan -= Time.deltaTime;
            if (lifespan <= 0f && this.gameObject != null) 
            {
                Destroy(this.gameObject); // Destroy particle when lifespan expires
            }
    
        void Start()
        {
            velocity = new Vector3(Random.Range(-2f, 2f), Random.Range(-2f, 2f), Random.Range(-2f, 2f));
            StartCoroutine(LifespanRoutine());
        }
    
        private IEnumerator LifespanRoutine() 
        {
             yield return new WaitForSeconds(lifespan);
             Destroy(gameObject);
        }
    

    P. S.
    A better approach is to set up object pooling instead of instantiating. Why even use a custom particle system? MonoBehaviour is quite a large wrapper for particles.