Persistent Particles in Godot

In Godot, particles don’t persist upon deletion. In other engines, if you delete a particle emitter, the already existing particles will complete their lifetime even if the emitter is removed. To fix this, I created a tiny class that intercepts the deletion process.

First, once it detects that it’s about to be deleted, it emits a signal to itself that stores the root of the scene and the last global position.
Then, once it starts being removed from the scene hierarchy, it cancels the deletion and uses the signal to reparent itself to the scene root and restore it’s last position.
Then it allows the particles to finish their lifetime, with some leeway, and finally after that fully deletes itself.

The code can be found below or on my Github Gist. My implementation is done in C#, but I presume it can be relatively simply converted to GDScript.

C#
using Godot;

public partial class PreservingGpuParticles3D : GpuParticles3D
{
    private bool _keep;
    public override void _Ready() => _keep = true;

    public override void _Notification(int what)
    {
        base._Notification(what);
        if (what == NotificationPredelete && _keep)
        {
            _keep = false;
            CancelFree(); //cancel our deletion once
        }
        else if (what == NotificationExitTree)
            CallDeferred(MethodName.PreemptiveDelete, GetTree().CurrentScene, GlobalTransform);
    }
    private void PreemptiveDelete(Node previousRoot, Transform3D transform)
    {
        if (_keep) return;
        GetParent()?.RemoveChild(this);
        previousRoot.AddChild(this);
        AmountRatio = 0;
        GlobalTransform = transform;
        GetTree().CreateTimer(Lifetime * 2).Timeout += QueueFree;
    }
}

Posted

in

by

Tags: