Reputation: 1
This is difficult to explain with typing...
I have a GameController scene (Node2D) that holds 3 instanced scenes within:
In the main scene (Level1.tscn) I instance the GameController scene and it "works" fine. The header bar is there with the score/label and the custom mouse cursor is there and the message box is there (but I have it hidden by default but if I toggle its visibility in the remote it will show up).
Here's where my confusion comes in...
If I attempt, in the GameController script, to manipulate any of those nodes in the GameController scene (the mouse, header, messages) they return as null and will throw an error. For example; if I try to update the score in the $HeaderBar/Control/score I get the following:
Invalid set index 'text' (on base: 'null instance') with value of type 'String'.
The code completion will autofill the node names as I type them (so it recognizes them in the group) but any attempt to reference/use them in script throws similar errors to above.
I'm very new to Godot so I'm sure it's just some misunderstanding I have on how this type of thing works but I'm stumped! Any insight is much appreciated!
UPDATE
I will try to simplify my explanation a bit (I have made some changes). Okay here is the object script:
extends StaticBody2D
onready var main = load("res://scenes/MainGame.gd").new()
func _ready():
pass
# mouse [left] clicked on object
func _on_trigger_input_event(viewport, event, shape_idx):
if Input.is_action_just_pressed("left-click"):
main.display_message("you [left] clicked on the object!")
the call to main.display_message() works. It does call the function but here is that function in the MainGame.gd
extends Node2D
onready var box = $Message/Control
onready var label = $Message/Control/Label
func _ready():
# hide the mouse cursor (will use custom cursor)
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
func display_message(msg):
label.text = msg
box.visible = true
It errors out because label (and box) are null. If I call display_message from the _ready function (in the MainGame.gd) it works as it should. Call it from outside (in the Object.gd) and the nodes are null for some reason.
Upvotes: 0
Views: 690
Reputation: 40295
This instances the scene as expected:
onready var main = load("res://scenes/MainGame.gd").new()
However, this code will run when the instanced scene is added to the scene tree:
onready var box = $Message/Control
onready var label = $Message/Control/Label
func _ready():
# hide the mouse cursor (will use custom cursor)
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
Yes, both onready
variables and _ready
will run when this is added to the scene tree.
And when do you add main
to the scene tree? I don't see where.
Then when you do this:
main.display_message("you [left] clicked on the object!")
Both box
and label
will still be null (which is the default value).
Thus, add it to the scene tree, for example:
func _ready():
add_child(main)
Except that does not work either, does it? Look at the code again:
onready var main = load("res://scenes/MainGame.gd").new()
You are instancing a script. A script. Not a scene. It will not have its children nodes and so on. You want to instance a scene, for example:
onready var main = load("res://scenes/MainGame.tscn").instance()
However, I find it odd that you are doing this in a StaticBody2D
. I don't think it makes sense that MainGame
belongs to a StaticBody2D
.
I suspect, you are instancing MainGame
in multiple places expecting it be the same instance. But it is not the same instance, it is a new instance.
Here is where I suggest you make MainGame
into a autoload, so there is a single instance that you can access from anywhere. However, perhaps that is not right either. Perhaps you should use a Signal Bus. See Why does this variable keep returning to its original value? which had a similar problem (they where trying to open a door, you are trying to show a message, but still).
Upvotes: 0