Cant reference main Node

Godot Version

4.4.1

Question

I have a button which when pressed calls OpenWindow(). In OpenWindow i want to instantiate a Scene in the main node, but i always get a main = NULL. I tried to change the node or have a reference through @export but it didnt work. When _ready is called it prints out the path and even the main node but when i then afterwards try to do the same thing with OpenWindow, which is called after _ready, there no longer is a path for the current node or main.In this code i tried to copy the path when i can get it in main but that also doesnt work. Here is the Code:

extends Control

var main

func _ready() → void:
print("self: ", self.get_path())
print("parent: ", get_parent())
print("parent.parent: ", get_parent().get_parent())
main = get_parent().get_parent()

func OpenWindow(ID:String):
print(main)
var CustomWindowScene = load(“res://Scenes/Windows/default.tscn”)
#print(ID)
#var CustomWindowScene = load(“res://Scenes/Windows/”+ ID +“.tscn”)
print(CustomWindowScene)
var window = CustomWindowScene.instantiate()
main.add_child(window)
And here is the Output:

self: /root/main/Manager/WindowOpener
parent: Manager:<Control#55129934575>
parent.parent: main:<Control#31037850950>

<PackedScene#-9223371974158316635>
The Structure is like this:
-main
-(irrelevant nodes like the button)
-Manager
–WindowOpener

It is not the solution, but I have copied and pasted your code and thanks to the “preformatted text” option it is more readable :tada:

extends Control

var main

func _ready() → void:
    print("self: ", self.get_path())
    print("parent: ", get_parent())
    print("parent.parent: ", get_parent().get_parent())
    main = get_parent().get_parent()

func OpenWindow(ID:String):
    print(main)
    var CustomWindowScene = load(“res://Scenes/Windows/default.tscn”)
    #print(ID)
    #var CustomWindowScene = load(“res://Scenes/Windows/”+ ID +“.tscn”)
    print(CustomWindowScene)
    var window = CustomWindowScene.instantiate()
    main.add_child(window)

You can use that too when typing:

Oh thx, i overlooked that

1 Like

What happen exactly when you click on your button ?
The game crashes ? Is there a line of code highlighted in red ?

If you do:

[...]

func OpenWindow(ID:String):
    var local_main = $main
    var local_man  = $main/Manager
    var local_win  = $main/Manager/WindowOpener

    print("Main: " + str(local_main))
    print("Man:  " + str(local_man))
    print("Win:  " + str(local_win))

    [...]

What do you get?

Your main is loading correctly. The “NULL” you are seeing is the Custom Window Scene, which means that the file path is most likely incorrect. The following code correctly loads an object into the main that you are looking for with the following scene tree:
image

var main

func _ready() -> void:
	print("self: ", self.get_path())
	print("parent: ", get_parent())
	print("parent.parent: ", get_parent().get_parent())
	main = get_parent().get_parent()
	await get_tree().create_timer(1.0).timeout
	OpenWindow("HELLO")

func OpenWindow(ID:String):
	print(main)
	var CustomWindowScene = load("res://Scenes/Windows/default.tscn")
	#print(ID)
	#var CustomWindowScene = load(“res://Scenes/Windows/”+ ID +“.tscn”)
	print(CustomWindowScene)
	var window = CustomWindowScene.instantiate()
	main.add_child(window)
`

You should consider using signals to add windows like this, as if you were to move this button down a level, you would need to change how to find main, where if you used a signal, a script running on main could detect that signal and put the element in the correct spot no matter where the original button is located on the scene tree. You can also use hooks to send in arguments like id.

1 Like

The Button calls the function like it should, i only get an error when i do something in the function, but here is the button code:

@export var Name: String = "name"
@export var ID: String = "default"
@onready var name_label: Label = $Name
var Desktop_Script = preload("res://Scripts/Windows/window_opener.gd").new()
func _ready() -> void:
	name_label.text = Name


func _on_pressed() -> void:
	print("AppButtonPressed")
	Desktop_Script.OpenWindow(ID)

I tryed it and when i called OpenWindow in _ready it worked fine but when i called it through a button press it once again returned NULL. Here is a photo of the tree, if i overlooked something there:


with the button being a child of Desktop. I also tryed and it worked with Signals, thank you for the Tip. I think i am gonna do it with Signals but does any one know why in the first place WindowOpener gets seemingly “unloaded” after _ready is called?

I once again get a NULL but only when i put it in OpenWindow not in _ready. Here is the output

Main: <Object#null>
Man:  <Object#null>
Win:  <Object#null>

I am pretty sure that Desktop_Script is not a node on the scene tree, but a class. Consequently, trying to get its parent will return null. You would want to load the actual node on the scene tree for the function to work

but how can i add a control node with a script to the scene tree when it is not spawned to code but in through the editor already attached to main?

You can use the get_node() function. The docs are here for how to use it Nodes and scene instances — Godot Engine (stable) documentation in English.

I’d suggest:

func OpenWindow(ID: String):
    print(get_tree_string_pretty())
    [...]

See if what it prints matches your expectations.

@hexgrid @frozen_coder ty for the help i tryed both get_node() and print(get_tree_string_pretty()) but i dont know how but window manager is somehow getting removed from the game tree. I didnt find a solution for that but i found a work around by Autoloading the script.