Fade down child particle effect once GameObject parent has been destroyed

Hi. What the title says really, I have a GameObject with a child particle effect that follows it around the screen. Once collected, the GameObject disappears but I’d like the particle effect to fade away slowly once the object pops out.

I’ve read about detaching the child, stopping the emitter and then destroying it after a set number of seconds which would be perfect if I could get any of the code I’ve been looking at to work.

I’m coding in js and hope someone can help me out.

Cheers

A script like this one should do the trick, attached to your Particle GameObject:

//Call this function when the parent object is collected
function ObjectCollected()
{
    //Unparent the effect
    this.transform.parent = null;
    
    //Stop emitting particles
    var particleSystem:ParticleSystem = this.GetComponent(ParticleSystem);
    particleSystem.Stop();
    
    //Start coroutine that will check if all remaining particles are gone
    CheckIfAlive();
}

function CheckIfAlive()
{
    var particleSystem:ParticleSystem = this.GetComponent(ParticleSystem);

    //Continue execution as long as the system is alive (i.e. there are still particles remaining)
    while(particleSystem.IsAlive())
    {
        //Check every 0.2 secs to avoid checking every frame for performances
        yield WaitForSeconds(0.2);
    }
    
    //Destroys the object when all of its particles are gone
    GameObject.Destroy(this);
}

I don’t code in JS but I think this is the right syntax.

This script has the advantage of automatically delete the GameObject once all particles are gone, you don’t need to manually specify a timer to destroy it.

Thank you very much Jean for the fast reply. That looks like it’s exactly what I need but when I try to collect the item (which should destroy the object and run ObjectCollided), the object doesn’t destroy itself and I get the following error:

NullReferenceException: Object reference not set to an instance of an object - and this seems to point to the line particleSystem.Stop();

Here is my code for the moment the collision occurs:

var Script : CoinParticleEffect;

function OnCollisionEnter (collision : Collision) 
{
	if(collision.gameObject.tag == "Coin")
	{
		Script.ObjectCollected();

		Destroy(collision.gameObject);

	}
}

And here is the code you gave me

    //Call this function when the parent object is collected
    function ObjectCollected()
    {
        //Unparent the effect
        this.transform.parent = null;
       
        //Stop emitting particles
        var particleSystem:ParticleSystem = this.GetComponent(ParticleSystem);
        print("worked");
        particleSystem.Stop();
       
        //Start coroutine that will check if all remaining particles are gone
        CheckIfAlive();
    }
     
    function CheckIfAlive()
    {
        var particleSystem:ParticleSystem = this.GetComponent(ParticleSystem);
     
        //Continue execution as long as the system is alive (i.e. there are still particles remaining)
        while(particleSystem.IsAlive())
        {
            //Check every 0.2 secs to avoid checking every frame for performances
            yield WaitForSeconds(0.2);
        }
       
        //Destroys the object when all of its particles are gone
        GameObject.Destroy(this);
    }

Any ideas why I’m getting the error? I’ve allocated var Script in the inspector too (declaring it this way was the only way I could get it to stop throwing incompatible variable errors at me).

On a side note I checked out your particle packs from your sig and they are superb. I’ll be buying Cartoon pack 1 in the next couple of days :slight_smile:

I’ve just thought, could this have something to do with the fact that the GameObject (and child particle effect) are prefabs that don’t currently exist in the scene?

Hmm, what do you mean they don’t exist in the scene?

This is how they should be in your Hierarchy (at least that’s what I understood from your original post):

CoinGameObject
    |
    -- EffectGameObject (with components ParticleSystem and CoinParticleEffect)

If the error points to particleSystem.Stop(), it means that the function GetComponent(ParticleSystem) has returned null, i.e. the component has not been found. There can be many reasons for this.
Indeed this should be called on Scene Objects and not on Prefabs; Prefabs would be used to Instantiate your Scene Objects from code (or place them through the Editor)

Also I see that there was an error in my script, GameObject.Destroy(this); should be GameObject.Destroy(this.gameObject); (else it only destroys the CoinParticleEffect component I believe)

Ahhh it appears the Particle object doesn’t include a Particle System but a Particle Renderer, Emitter and Animator. Are there functions for these to achieve the same result as with a System in your code above? I tried myself but kept getting the error "Coroutine couldn’t be started because the game object “CoinTrail” is inactive! trying to run CheckIfAlive().

Oh, in that case it means that your effect uses the old Particle System (pre-Unity 3.5) instead of the new one (called “Shuriken”).

It might be simpler actually, because these systems could destruct themselves after emission.

Go into the GameObject’s inspector, and in the Particle Animator, check the “Autodestruct” box.

Then, use this script:

function ObjectCollected()
{
    //Unparent the effect
    this.transform.parent = null;
    
    //Stop emitting particles
    var particleSystem:ParticleEmitter = this.GetComponent(ParticleEmitter);
    particleSystem.emit = false;
}

However, my advice is to use the new Particle Systems in the future: they are more optimized and more powerful!

Thanks, I’ve tried that but it doesn’t want to detach the child.

The script definitely runs but they do not detach and the Particle Effect disappears with the gameobject being destroyed. I even tried it with a time delay

function OnCollisionEnter (collision : Collision) 
{
	if(collision.gameObject.tag == "Coin")
	{
   
     
		CoinXP.coins += 1;
		coins.text = ("Coins: " + CoinXP.coins.ToString ());
		experience.text = ("XP: " + CoinXP.xp.ToString ());
		CoinParticleEffect.ObjectCollected();
		Destroy(collision.gameObject,5);

	}
}

And

    function ObjectCollected()
    {
        //Unparent the effect
        this.transform.parent = null;
        print("TEST");
       
        //Stop emitting particles

    }

(Without the Particle stop emitting code) and nothing.

Also when I add the Particle Stop emitting code, it turns off the emitter tick from the Prefab and not the instance in-game so all other instances of that prefab start with particles off.

It looks like you have linked the Prefab to the CoinParticleEffect variable on your script handling the collision, instead of the Scene object.
That would explain why nothing happens to the Scene object!

Could you detail how you create the collectible objects in your Scene?

They are Gameobjects (cubes) that have had the particle effect attached as a child and are then turned into prefabs. The original is then destroyed so it can be instantiated when needed.

The code for creating them is:

var numofcoins = Random.Range(1, 5); // random number of coins between 1 and 4

var numofcoins = Random.Range(1, 5); // random number of coins between 1 and 4
			
    		for (var i = 0; i < numofcoins; i++)
    		{
    			var newcoin = Instantiate(Coin,new Vector3(transform.position.x,transform.position.y,transform.position.z+1.5), Quaternion.identity);
    		
    			var xspeed = Random.Range(-200, 200); // determine speed of coin on creation

    			var zloc = Random.Range(5, 10); // determine depth of coin on creation
    		
    			var decimal = Random.value; // add decimal for depth of coin
    		
				zloc = zloc + decimal; //add decminal to depth position
				print(xspeed+decimal);
				newcoin.rigidbody.AddForce(xspeed+decimal,0,0); //move the coin by the xpeed (+decimal)
			
				newcoin.transform.position.z = zloc;
			}

Ok well in your project, have you created the prefab this way?:

In the Hierarchy:

  • Create the Cube object
  • Create the Particle object
  • Drop the Particle object on the Cube so make it its child
  • Add the “Object Collected” script to the Particle object
  • Add the “On Collision Enter” script to the Cube object
  • Drag the Particle object to the “Object Collected” variable field on the Cube’s script
  • Drag the Cube object to the Project panel to create a Prefab

Then drag that Prefab to the code instantiating the Cubes.

On second thought, where is your OnCollisionEnter function called? I see an inconsistency:

    CoinParticleEffect.ObjectCollected();
    Destroy(collision.gameObject,5);

You should call ObjectCollected on the collision.gameObject’s script; something similar to that:

    collision.gameObject.getComponent(ObjectCollectedScript).ObjectCollected();
    Destroy(collision.gameObject,5);

I FINALLY got it working! The onyl way it would have it was by controlling the split and the emitter stop in the collision object outside of the prefab. I added

	collision.transform.Find("CoinTrail").particleEmitter.emit = false;
		collision.transform.DetachChildren();
		Destroy(collision.gameObject);

And it takes care of it!

Thanks again for all your help and for the awesome Particle pack, having a lot of fun with it.