The problem is that in the child _ready() function there is a method that needs that variable to work, but that function is called before the variable arrives from the parent, resulting in failure.
Child:
var variable: String
func _ready() -> void:
function(variable)
I am not certain about best practices, but what you can do is:
Access your parent by name using $. This is most certainly not best practice if your child is supposed to be reusable.
If your child is added in code, use the _init function by overriding it.
Worst practice would be using get_parent.
I have another idea but I don’t think if that will work and I don’t think it would be best practice. You could probably use @extern to enter the parent path from the parent scene to ensure reusability. I recommend using asserts to make sure the variable is set however to avoid unforeseen runtime issues.
I would not recommend accessing the parent from the child, for 2 reasons:
nodes generally “own” and know about their children, but should not know about or rely on their parents
as you’re seeing, the _ready() functions get called from the lowest point in the tree, traveling upwards (so at each node you can rely on its children already being ready). The parent’s property you’re trying to read might be available and ready to use, but since the parent’s _ready() hasn’t run yet, you shouldn’t count on that
@teivfik 's solution is a good one. I’ll add another example expanding on their first suggestion, because I believe there’s merit to the design that you use Signals to bubble messages up, and rely on method calls going down (so that the child continues to remain oblivious about its parent - the parent should already know about the existence and type of the child):
child:
private bool initialized;
private string vari = "Not Initialized"; // value is optional, but could help troubleshooting
public override void _Ready() {
initialized = false; // redundant but illustrative
}
public void Initialize(string variValue) {
vari = variValue;
initialized = true;
}
// other methods can check `initialized` and fail/handle appropriately if `false`
// (IMO printing an error, but not throwing an exception, is the
// best practice here)
parent:
public string ChildValue { get; set; }
public override void _Ready() {
child.Initialize(ChildValue);
}
(sorry not sorry about the C# instead of gdscript )
I also like global variables and access them with get/set. But when calling down to my children, then there are some good reads online. This site was actually pretty good at explaining things within godot.
In a post talking about best practices, I don’t believe it’s correct to encourage programmers to use global variables such as others have suggested.
Global variables should be used sparingly and only for properties or functions that architecturally could be used by all nodes in a scene.
And looking back, I made a mistake in my original post - as @emberlockgames has pointed out, it’s not good practice to access the parent from a child node, so my approach using signals isn’t the best, and child initialization should be done through a function called in the parent script.
There’s always a time and place to use global variables. They’re easy to use and easy to understand, especially when you want to use databases. Like when you create JSON files to store all your Dialog, Quests, Items, etc. Or when you decide to translate your game.
But like most things, “It depends”, is a very common answer.