0 votes

Hi all

I have a smoke trail GPU2DParticles effect attached to a rocket. If the rocket explodes and is removed from the tree, I'd like the effect to be reparented to another node (root in the example), so that the trail remains and does not immediately disappear with the rocket.

I used to do this explicitly (reparent on collision -> explosion), but I am wondering if this could be done on e.g. tree_exiting or another signal or method call on a script on the effect itself.

extends GPUParticles2D

func _ready() -> void:
    connect("tree_exiting", trigger_reparent)

func trigger_reparent() -> void:
    # Silently does not work.
    # call_deferred("reparent")

    # Error: trigger_reparent: Parent node is busy setting up children.
        reparent()

func reparent() -> void:
    var gp = global_position
    self.get_parent().remove_child(self)
    self.get_tree().root.add_child(self)
    self.global_position = gp

If I immediately try to reparent in tree_exiting, I get the cryptic "Parent node is busy setting up children." (I assume the parent node state is just not ok for removing children between tree_exiting and tree_exited)

What is the best way to reparent e.g. effects on parent death? Thanks!

Godot version v4.0.alpha5.official [d7d528c15]
in Engine by (57 points)

1 Answer

0 votes
Best answer

The effect could be parented to the main scene this way I think.

Sending the effect to a child of the main scene on a signal, rather than to the rocket itself, and having the main scene recieve the particles instead. The particle node would need to be its own scene

-something like this in the particles script-
func startparticleemit(.....)
emit_signal('smoke......)

-something like this added to main scene script-
func onsmokeemit()
add
child(smoke)
smoke.start

That way although the rocket made the smoke start, it is never part of the rocket, so once thats exploded you should still have the smoke.

you might need to figure out additional code how the main scene particles position follows the rocket once its moving, but thats probably fairly simple!

by (69 points)
selected by

Thanks for your answer!

I've now set it up as follows:

image RemoveTransform2D > Effect">

And the Smoke effect has a script to detach and set itself as the target of the RemoteTransform2D:

extends GPUParticles2D

func _ready() -> void:
    var parent = self.get_parent()
    if parent.is_class("RemoteTransform2D"):
        # "Attach" to old parent.
        reparent.call_deferred(parent)

func reparent(parent) -> void:
    # Reparent.
    var gp = global_position
    var root = get_tree().root
    parent.remove_child(self)
    root.add_child(self)
    self.global_position = gp
    # Point RemoteTransform2D to this effect.
    parent.remote_path = get_path()

And then, when the rocket Engine goes away, I'll stop the effect by getting the effect via its remote_path.

Works fine so far!

Yay, glad it worked, I forgot the RemoteTransform node even existed, so I guess that makes things even simpler!

It does! Still, handling effects correctly via reparenting etc is a surprisingly manual affair in Godot.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.