how can I free a Particles2D when all particles disappeared?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By alexzheng
:warning: Old Version Published before Godot 3 was released.

I add a particles2d and set the lifetime = 1 and emit timeout = 1
I want to free the particle2d object at the time when all particles become invisible, but I can not determine when to do this.
if I enabled the _process, it’ll stop automatically after all particles disappeared.

You can implement your own stop function, that disables emitting particles, then waits for x seconds, where x is the lifetime of the particles, and then calls queue_free().

timoschwarzer | 2017-09-02 13:33

when lifetime = 1 and emit timeout = 1, I thought it takes 2 seconds when the last particle become invisible, but the process runs only for about 1.5s, so I can not tell the exactly point when the last particle is invisible.
Of course, if I only need to free the particles2d, there’s some simple way to just use a timer to free it after about 2 or some more seconds.
But I want to free it immediately after all particles become invisible.

alexzheng | 2017-09-02 13:45

Can I ask why you want to do this? If the Particles2D node is not emitting, it’s not visible or doing anything, so why do you need to free it?

kidscancode | 2017-09-02 16:10

When all particles of this node become invisible, I do not need it any more, it should be removed to free its memory.

alexzheng | 2017-09-03 00:25

How much memory do you actually think is being used by a non-emitting particle node? You’re wasting your time trying to solve a problem that isn’t a problem.

The golden rule of programming: don’t try to optimize something that doesn’t need optimization.

kidscancode | 2017-09-03 00:31

No matter how much memory it takes, if the amount of nodes is large, it will take up a lot.

alexzheng | 2017-09-03 00:46

More than adding a Timer node to each one in order to free it? Are you going to also free all the timers? How many more CPU cycles for adding all those nodes to the queue for freeing? If this functionality were important, don’t you think the Particles2D node would have it?

Just discussing all this has wasted far more resources than your particle node probably ever will. How much more of your game could you have made using this time instead?

I’m being very serious. Look up “premature optimization” - it’s a trap novice programmers fall into, and it’s always a waste of time. When you actually have a performance problem, that’s when you try to solve it.

kidscancode | 2017-09-03 00:55

Thanks for your reply.
Yes, I agree with you. it’s overload to add a timer to free. That’s the reason why I ask for a solution here.
But I’m afraid I can not just leave the particles node, in my game play, it may spawn thousands of or even more particles in one level.(I’m lazy to use a pool to reuse the emitter :slight_smile: ), the memory can not be ignored.

alexzheng | 2017-09-03 01:09

How do you know? Have you measured? Do you have profiler output showing how much memory a non-emitting emitter will use? With thousands of nodes, there are potentially other things that are going to cause a memory or frame rate problem. My point is that it sounds like you’re just guessing.

kidscancode | 2017-09-03 01:43

For example, a match game like bejeweled, spawn a particles2d node when remove an item, or for a shoot game, spawn a particles2d node for each bullet explosion, it may spawn lots of particles node during a level, do you think all these nodes maybe leave stay in the memory until the game scene is removed? Or am I misuse the particles this way?

alexzheng | 2017-09-03 10:00

For a situation like that, I wouldn’t spawn a new Particles2D for each effect. Just move it to the location and start the effect.

kidscancode | 2017-09-03 16:23

The same problem for recycling the node for reuse is how to determine when a particles node finished?

alexzheng | 2017-09-04 00:02

Well, you can tell if it’s finished emitting, and that’s all that matters. If it’s not emitting, move to the new place and start emitting. The already-emitted particles will fade out and disappear as normal. Depending on how frequently you’re spawning new nodes that need the effect, that might be sufficient. Might need to play around with the timing.

kidscancode | 2017-09-04 00:22

Yes, For my situation, use a pool to reuse the nodes is a more elegant solution.
But how to tell if it’s finished emitting and ready for reuse?
using is_emitting?
I test with this code, but, when is_emitting return false, there are still particles visible on the screen, I think the particles2D node is not yet ready for reuse at the point.

Another problem, it seems the _fixed_process callback will be stopped automatically, and I can not do timing in the _fixed_process to recycle the particles2d node after delay some time.

func _fixed_process(delta):
if not is_emitting(): #it’s not ready for recycling yet
get_tree().set_pause(true) #set pause to check clearly if any particles emitted by this particles2d node are visible

alexzheng | 2017-09-04 02:24

:bust_in_silhouette: Reply From: eons

If you set timeout 1, of course will stop emitting after 1 second, with or without process.

For the question, I don’t know why you need to get rid of the emitter but a way could be:
Add a Timer o the Particle2D node and keep checking every frame (with a script on the emitter).
If is not emitting anymore fire the timer with a particle lifetime time (if is random, set a max) and stop processing the emitter.
On timeout, free the emitter.

What I need is something like one shot particles node, it emits some particles and freed after it become invisible.
I don’t want to overload to add a timer, I try to free it when specific time escaped in _process, but it seems the _process callback will auto set to false and stop called.

alexzheng | 2017-09-03 00:41

I think it should be better to have an API to set_auto_free to true to free the node when the emitter stop and all particles are invisible

alexzheng | 2017-09-03 00:54

I didn’t knew that the particle process was linked to the actual process, interesting.

Is more common to recycle the emitter or leave it linger around until the scene closes, the cost of leaving it there until the parent is freed may be less than trying to free it.

eons | 2017-09-03 20:21

Yes, the _process will stopped is surprising.
If it will not stop, I can do recycle or free in the _process after some seconds without adding a timer.

alexzheng | 2017-09-04 02:38

:bust_in_silhouette: Reply From: Cerno_b

What I did is to add each one-shot emitter into a group and then loop over that group and free all emitters that are not emitting:

func free_emitters():
	for emitter in get_tree().get_nodes_in_group("one_shot_emitters"):
		if not emitter.emitting:
			emitter.queue_free()
:bust_in_silhouette: Reply From: CakeLover

Incase anyone runs by this question and has their particles set to one_shot=true

you can create a timer and free the particles like this:

get_tree().create_timer(particles.lifetime,false).connect("timeout", particles, "queue_free")

Though this worked in my case I’m not sure how this will be effected by changing the various properties in ParticlesMaterials so I might be wrong altogether