Quick answer: After a one-shot, set emitting = false only by the system itself; manually flipping emitting = true may not retrigger. Call restart() to reset the timeline and re-fire the burst. For pooled nodes, always restart on reuse.

Here is how to fix Godot GPUParticles2D bursts that fire on first activation but stay silent on every subsequent attempt. You set one_shot = true for explosion effects, fire one explosion, and the next attempt at the same effect produces nothing. The trick is using restart() rather than toggling emitting.

The Symptom

A GPUParticles2D with one_shot fires once correctly. After completion, calling emitting = true does nothing. The system stays empty.

What Causes This

One-shot end state. When a one-shot completes, internal state is in a finished position. Re-toggling emitting is interpreted as “already done” rather than “start over.”

Process priority. Some Godot versions need a frame between disable and re-enable for the system to reset. Calling restart eliminates this race.

Pooled reuse. Pooled nodes retain finished state when re-attached.

Wrong texture/material. If the ParticleProcessMaterial has lifetime randomness with seed quirks, all particles can have lifetime 0 on second emission.

The Fix

Step 1: Use restart for one-shots.

extends Node2D

@onready var explode: GPUParticles2D = $Explosion

func trigger_explosion(at: Vector2):
    explode.global_position = at
    explode.restart()

restart resets the internal time, randomness, and re-fires the one-shot in one call.

Step 2: For pooled effects, restart on reuse.

func _spawn_from_pool(pos: Vector2) -> GPUParticles2D:
    var p: GPUParticles2D = pool.pop_back()
    if p == null:
        p = explode_scene.instantiate()
        add_child(p)
    p.global_position = pos
    p.restart()
    return p

Step 3: For continuous emitters, toggle emitting. If one_shot = false, simply set emitting = true or false. Restart is unnecessary and resets the entire ongoing emission.

Step 4: Verify lifetime and rate. A lifetime of 0 or rate of 0 produces no visible particles. Open the ParticleProcessMaterial and confirm reasonable values.

Step 5: For visual debug, enable visibility_aabb_changed. Goes hand-in-hand with a tight visibility rectangle. If the AABB is wrong, particles can be culled even when emitted. Set visibility_rect wide enough to encompass the burst.

Performance Tradeoff

restart re-runs the whole emission pipeline. For 60-times-per-second emitters this is wasteful. Use it only for one-shots or rate changes; ongoing emission should toggle emitting.

“restart() for one-shots and pool reuse. emitting toggle for continuous. Pick the right tool.”

Related Issues

For shader uniforms, see Shader Uniform Not Updating. For tween signals, see Tween Finished Signal.

restart() each spawn. visibility_rect wide enough. Burst fires every time.