Attention | Topic was automatically imported from the old Question2Answer platform. | |
Asked By | skonar2 |
So. I’m trying to understand my options for moving data around scenes, so I’m experimenting. My current experiment is trying to work out if it’s possible to make a node that can, when the scene switches, jump into the new scene. Without reference to any other code I make - just that node and the script in the node.
The way I’m trying to do this is to have a node - traveller - which is instanced with a button push. I can then name it, so I can be sure I have the same traveller in the next scene.
Traveller listens to the scenetree. When it changes, traveller runs return to see if the current scene (from get_currentscene) is different to the scene it thinks it’s attached to. If it is, it tries to attach to the new current scene.
If its parent node exits, it attempts to _leave and attach to the root node, so it doesn’t get deleted. (As I understand it, a node not attached to anything, which also isn’t a singleton/autoload, deletes itself?)
Traveller is a Node2D, with a child TextureButton, child Button named NameButton, child Label, and child LineEdit.
Here’s my code, and I will explain a bit more below:
extends Node2D
## Traveller. This is the Traveller, a test for moving nodes and information between scenetrees. Traveller has a unique name attached to a label node, with data fed in from a LineEdit node.
var myroot
var mycurrentscene
# Called when the node enters the scene tree for the first time.
func _ready():
_initvars()
myroot.connect("tree_changed",self,"_return")
get_parent().connect("tree_exiting",self,"_leave")
connect("tree_exited",self,"_perish")
func _initvars():
myroot = get_tree()
mycurrentscene = myroot.get_current_scene()
func _return(): # Check if the current scene has changed, and if it has, jump to the new current scene.
if mycurrentscene != myroot.get_current_scene() && myroot.get_current_scene() != null:
print("Traveller returning... from " + str(mycurrentscene) + " to " +
str(myroot.get_current_scene()) ) # An announcement for debug
get_parent().remove_child(self)
myroot.get_current_scene().add_child(self)
_initvars()
func _leave(): #Detach from parent node, and try to attach to the scene tree root?
print("Traveller Departing " + str(mycurrentscene)) # Announcement for debug
get_parent().remove_child(self)
myroot.get_root().add_child(self)
_initvars()
func _perish(): # Announcement for debug, announce if this node has left the tree. At which point it gets deleted? I think?
print("Traveller has perished.")
func _on_NameButton_pressed():
$Label.text = "My name is " + $LineEdit.text
pass # Replace with function body.
func _on_TextureButton_pressed():
print(str(get_parent())) # Debug to make sure I know what Traveller is attached to.
pass # Replace with function body.
Okay. When I run this, the idea is that the _return func should trigger and swap over to the current scene.
Here’s what I get out of the debug announcements from a run attempt:
Traveller Departing [Control:1195]
Traveller has perished.
Traveller returning... from [Deleted Object] to [Node2D:1649]
Traveller returning... from [Deleted Object] to [Node2D:1649]
Traveller returning... from [Deleted Object] to [Node2D:1649]
(last line repeats until stack overflow)
The editor crashes and throws a ton of this error at me:
E 0:00:03.581 _notification: Condition "!get_viewport()" is true.
<C++ Source> scene/main/node.cpp:99 @ _notification()
<Stack Trace> Traveller.gd:23 @ _return()
Traveller.gd:23 @ _return()
Anyone know what’s going wrong? Any advice for what I should be doing? Am I trying to do something that flat out isn’t supported by the engine, and I can’t do this with an individual script on an individual node? It 100% requires me to use other nodes and scripts?
A copy of the project can be found at: Dropbox - TravellerTrouble.zip - Simplify your life
There’s a button to create a traveller, and one to switch between two scenes. (It’s also really just a mess of code I’m using to try and understand some stuff.)
EDIT:
Playing around with this, the error seems to be very much tied to the line get_parent().remove_child(self)
, and the viewport. Is detaching children from the viewport something that needs to be done differently?
EDIT 2:
I got it sort of working by adding a yield to my code here:
func _return(): # Check if the current scene has changed, and if it has, jump to the new current scene.
if mycurrentscene != myroot.get_current_scene() && myroot.get_root() == get_parent() && myroot.get_current_scene() != null:
print("Traveller returning... from " + str(mycurrentscene) + " to " +
str(myroot.get_current_scene()) + " Parent is " + str(get_parent())) # For debug
yield(get_tree().create_timer(0.2), "timeout") # Will a pause help? It helped. WHY?
get_parent().remove_child(self)
myroot.get_current_scene().add_child(self)
_initvars()
request_ready()
But I don’t understand WHY adding the yield on a short timer made it work. Can anyone explain this to me?