- Home /
How to destroy / hide a single particle?
I tried using ParticleSystem.SetParticles to change the lifetime of a particle, but it reset the other particles. Is there a way to simply destroy / hide / move one particle without resetting the system?
Answer by Wolfram · Jun 22, 2012 at 08:26 PM
What exactly did you do? As with the old system, I would guess you first have to get all current particles with ParticleSystem.GetParticles, then remove the particle you want from that array somehow, and then reassign that new array back to the ParticleSystem (but read on).
In the old particle system (ParticleEmitter), instead of removing the particle physically from the array, it was enough to set its energy to 0. This way the ParticleEmitter will take care of the rest, recognize the particle als being dead/finished, and remove it itself from its internal particle array. I would assume you can do the same with Shuriken?
EDIT: I tested this now for myself. The Shuriken works the same as the old system, you can modify/remove/add individual particles. BUT the API call to get the existing particles is just plain weird and stupid, I have no idea why anyone would program it in such a way: Instead of simply returning the particles array, which you then can modify, you must provide your own array, which is passed to GetParticles(). After this call returns, your particles array has been filled with the information of the existing ParticleSystem. This is completely unintuitive, and would probably be frowned upon and discouraged in any programming guide, to call a function "GetXXX", but then have it modify an array you have to initialize and pass into it.
tl;dr: Try this example instead, it will work. Create a new ParticleSystem with default emission behaviour, and attach this script to it. (Note, when using the menu GameObject->CreateOther->ParticleSystem, the ParticleSystem will initially have an x=270 rotation, for whatever reason)
using UnityEngine;
using System.Collections;
public class ParticleSystemTest : MonoBehaviour {
private ParticleSystem ps;
void Start () {
ps=GetComponent<ParticleSystem>();
}
void Update () {
// initialize an array the size of our current particle count
ParticleSystem.Particle[] particles=new ParticleSystem.Particle[ps.particleCount];
// *pass* this array to GetParticles...
int num=ps.GetParticles(particles);
Debug.Log("Found "+num+" active particles.");
for(int i=0;i<num;i++){
if(particles[i].position.z>5) // large local z: let particle drop down
particles[i].velocity-=Vector3.up*0.1f;
if(particles[i].position.x>1) // positive x: make it red
particles[i].color=Color.red;
if(particles[i].position.x<-1) // negative x: make it die
particles[i].lifetime=0;
}
// re-assign modified array
ps.SetParticles(particles,num);
}
}
This appears to do nothing...
var particleTotal = 7;
private var particles = new ParticleSystem.Particle[particleTotal];
function Update ()
{
particlesLength = particleSystem.GetParticles(particles);
particles[0].lifespan = 0;
particles[1].color = Color.red;
particles[2].position = Vector3.zero;
}
You need to reassign the particle system.
particleSystem.SetParticles(particles,particles.length)
Yeah that's my problem Vicenti. When I do that, the particle system resets.
What I'm trying to achieve is a set of orbs that bounce out that the player can collect. They'll bounce out fine and will slowly disappear over the lifetime rate, and I can detect when a player has collected a particle. I just don't know how to make that individual particle disappear. Using SetParticles the particles all bounce out all over the place again and reset the lifespan.
Well, in the code fragment you posted you are creating an empty array of particles, so there won't be happening much. Usually, this array is initialized by the ParticleSystem. If you create your particles entirely by yourself, generate an empty array as you did, fill it with your desired values (without using GetParticles!), and then apply it with SetParticles, all this in some initialization routine such as Start().
Note that your code fragment shouldn't compile, since there is no property "lifespan", it is called "lifetime". Also note that in your code you set the first particle's lifetime to 0, so the ParticleSystem will automatically remove it before the next Update. This reduces the length of your particles array by one, and at a starting size of 7 you should be almost immediately run into an "array out of bounds" error.
There is nothing "weird and stupid" about filling an array passed to the particle system. That is how you avoid an expensive memory allocation every time you call GetParticles. No memory to allocate if you can reuse the same array.
Answer by Essential · Jun 23, 2012 at 07:36 PM
So the more I research this, the more I'm beginning to believe that it's impossible to adjust the properties of a settled particle without the whole particle system starting the animation from scratch. If anyone could just confirm this that would be great. Then I can start investigating another option for my bouncing collectable coins...
I believe this ties into my question (http://answers.unity3d.com/questions/802603/can-i-force-shuriken-to-recalculate-its-bounds-pro.html). I too would like to call SetParticles() without the particleSystem resetting/stopping. I mention this because if you get it to work you might run into the next problem which is culling with scripted shuriken systems. $$anonymous$$aybe have a look.
Answer by brilliancenp · Feb 27, 2014 at 03:41 AM
If what you are trying to do is make a particle dissapear on collision with a player object, or any object for that matter it can be done. It seems like it would be inefficient to do it this way but I have seen no slowdown and I have done this with systems with many particles.
The difference here is that I am using a monobehavior, below I will call it MyParticleSystem, to copy the particle array into its own array every update. So every update I am using the behaviors ParticleSystem.Particle[] to Get and set the particles. This way I can expose the array and have access to modify it between updates without having to worry about doing a particleSystem.SetParticles() at an odd time risking some unwanted behavior.
If you get the collision event using OnParticleCollision on the Player character.
void OnParticleCollision(GameObject other)
{
ParticleSystem particleSystem = other.GetComponent<ParticleSystem>();
MyParticleSystem mySystem = other.GetComponent<MyParticleSystem>();
if(null != mySystem)
{
//here we will get the particle list from the attached MyParticleSystem
ParticleSystem.Particle[] points = mySystem.GetParticleList();
ParticleSystem.CollisionEvent[] collisions = new ParticleSystem.CollisionEvent[particleSystem.safeCollisionEventSize];
int numberOfCollisions = particleSystem.GetCollisionEvents(this.gameObject, collisions);
int j = 0;
while(j < numberOfCollisions)
{
//find the particle closest to the collision
Vector3 collisionLocation = collisions[j].intersection;
float closestDistanceToIntersect = float.MaxValue;
int closestParticleNumber = -1;
for(int i = 0; i < this.points.Length; i++)
{
ParticleSystem.Particle p = points[i];
float distanceFromIntersect = Vector3.Distance(p.position, collisionLocation);
if(distanceFromIntersect < closestDistanceToIntersect)
{
closestDistanceToIntersect = distanceFromIntersect;
closestParticleNumber = i;
}
}
//I am pretty sure lifetime has to be set to less than 0.0f to get rid of it
points[closestParticleNumber].lifetime = -1;
}
//assign the list back to the object
mySystem.SetParticleList(points);
}
}
This works nicely for me. This is a much condensed version of what I use however. I am not saying it will work for systems with 2000+ particles I have tested with the upwards of 800-900 with no slowdown in a test environment. I found that if you dont use the behavior to keep track of the particle list then the OnParticleCollision script will have to use the particleSystem.GetParticles(particleArray[]) and particleSystem.SetParticles(particleArray[], arraylength). SetParticles will remove any particles with a lifetime < than 0 so if the collision script runs it can cause unwanted behavior sometimes.
Looks like to be a smart solution, but I can not do it. Could you please describe a little wider the process?
Apologies for the dumb question, im kinda new to this. whats the difference between: ParticleSystem particleSystem = other.GetComponent(); $$anonymous$$yParticleSystem mySystem = other.GetComponent<$$anonymous$$yParticleSystem>(); And what does each represent? Sorry, if this has already been answered.
I keep trying to find GetParticleList(); but there's no documentation. How did you get this to work? Or is GetParticleList a substitute for something? I've tried several different methods of getting a particle list, but I keep getting steered towards particleCount, and the compiler rejects that every time. Same Issue trying to find SetParticleList. Was this ran on Shuriken, or Legacy? I'm using Unity 4.6.1p2.
Or If someone has a better way of accessing particles on a individual collision level from a game object. I am all ears.
Thanks everyone!!
$$anonymous$$yParticleSystem is a helper class @brilliancenp wrote, he did not post the code for it. Get/SetParticleList are methods defined in this class, so they are not Unity methods, or part of the Unity class ParticleSystem.
Your answer
Follow this Question
Related Questions
How to destroy live particle in Shuriken 1 Answer
Shuriken particle System - change velocity by trigger 0 Answers
Particle System lifetime not affecting particles 0 Answers
Changing startRotation from ParticleSystem on script does not work 1 Answer
How to make particles react to movement of particle system 4 Answers