I apoogize in advance if this has been asked. I couldn’t find it.
I have a game object that emits particles as it flies. It is basically a magic bolt type effect. The game object is destroyed when it hits an enemy, but unfortunately all of the remaining living particles are also destroyed simultaneously instead of flickering out as they should.
Is there an easy way to prevent this? Please keep in mind that I am a noob to Unity, and a poor coder in general.
If you want to have the particle effect fade out nicely, put the particle effect on a child object of your magic missile and then have something to the effect of the following code on the missile itself:
public ParticleEmitter emit;
// blah blah rest of code
// Call this immediately before you destroy your missile
public void DetachParticles()
{
// This splits the particle off so it doesn't get deleted with the parent
emit.transform.parent = null;
// this stops the particle from creating more bits
emit.emission = 0;
// This finds the particleAnimator associated with the emitter and then
// sets it to automatically delete itself when it runs out of particles
emit.GetComponent<ParticleAnimator>().autoDestruct = true;
}
And then you’re all set! Assign the particleEmitter object to your script in the inspector, and then when you want to delete your missile, call that bit of code and it will neatly separate the particle effect at the same time as ordering it to clean itself up when it’s finished.
I used a little from the other answers here and this code works great for me. This code is for multiplayer setups, remove the “[Command]” and “Cmd” if you are not using NetworkBehaviour for multiplayer. Also make sure to change your Stop Action to “destroy” in your Particle System.
public ParticleSystem emit;
// blah blah rest of code
// Call this immediately before you destroy your missile
[Command]
void CmdDetachParticles()
{
// This splits the particle off so it doesn't get deleted with the parent
emit.transform.parent = null;
// this stops the particle from creating more bits
emit.Stop();
}
For anyone having this problem in Unity5, this solution won’t work as-is.
Unity 5 took away many legacy things, ParticleAnimator included.
The solution I found and what should work to most people using U5 is as follows:
This is a code that puts AutoDestroy back to the particle. You just create a new script, put this code inside and then put the code inside the particleSystem you want to terminate:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class AutoDestroy : MonoBehaviour
//This code destroys the particle's GameObject once it's Start Time is over.
//Also, if you're having issues with particles vanishing after you get far from them, just set their XYZ Scale values to 2, 2, 2
{
private float timeLeft;
public void Awake()
{
ParticleSystem system = GetComponent<ParticleSystem>();
timeLeft = system.startLifetime;
}
public void Update()
{
timeLeft -= Time.deltaTime;
if (timeLeft <= 0)
{
GameObject.Destroy(gameObject);
}
}
}
Now, to the projectile gameObjects script:
public ParticleSystem emit;
void OnTriggerEnter2D(Collider2D other) //Can be other ways of detecting
{
// This splits the particle off so it doesn't get deleted with the parent
emit.transform.parent = null;
// this stops the particle from creating more bits
emit.emissionRate = 0;
//This destroys the projectile
Destroy (gameObject);
}
Thanks for all the answers above, here is the one that work for me. Other solution for Unity 5 without using autoDestruct . Using ParticleSystem.IsAlive().
private void Update()
{
// check if the particle system still alive.
if (_detached
&& null != _curParticleSystem
&& !_curParticleSystem.IsAlive())
{
if (null != _parent)
{
//put it back to the parent.
transform.parent = _parent;
_detached = false;
}
else
{
// destroy it.
Destroy(this);
}
}
}
public void Detach()
{
_detached = true;
_parent = transform.parent;
// splits the particle off so it doesn't get deleted with the parent
transform.parent = null;
_curParticleSystem = GetComponent<ParticleSystem>();
if (null == _curParticleSystem)
{
return;
}
// stops the particle from creating more bits
_curParticleSystem.Stop();
}
* foreach(ParticleSystem ParticleSystem in ParticleSystemToDestroy.GetComponents()){* * ParticleSystem.emissionRate = 0;* * ParticleSystem.Stop ();* * }* * }* } You call it like this: public void SwordSlash_Finished () { ParticleDestroyer.Destroy(Particle); Destroy(gameObject); } So the ParticleDestroyer is a class which uses static methods, the class itself is not static because I want to use the Update function, which can only be used off of classes that are derived from MonoBehaviour. This means you need to attack the script to a GameObject in your scene. The Destroy function halts the particle systems activities and the CheckAndDestroyDeadPArticleSystems function constantly scans all particle systems and if there are no dead alive particles left it can safely destroy the GameObject. It also accounts for GameObjects with multiple ParticleSystems attached to them. Your welcome.
Anybody still looking for nice solution what I found that works best for me is just to instantiate the particle system on the position I want (e.g. place where player collided with something). Particle system does not have to be attached to the player it can be just a prefab.
private void Explode()
{
// If particle system is not set no need to do anything
if (explode == null) return;
// Instantiate particle system
Instantiate(explode, transform.position, Quaternion.identity);
// Set the position of the particle system to players position
explode.transform.position = gameObject.transform.position;
// explode :)
explode.Emit(20);
explode.Play();
}
Other not so elegant solution I use is to disable the sprite rendered on the player.