Godot Version
4.4
My parent node instantiates a child node in _ready(). Afterwards my child node tries to create a parent variable as in var parent: Parent, but it is null. However, when I use get_parent(), it works fine. Any ideas? Thank you!!
4.4
My parent node instantiates a child node in _ready(). Afterwards my child node tries to create a parent variable as in var parent: Parent, but it is null. However, when I use get_parent(), it works fine. Any ideas? Thank you!!
It’s a race condition. But posting your code makes it a lot easier to diagnose.
Not a prob. I’m thinking it has to do with how and when _process() and _ready() run but I’m not sure.
Here’s the parent:
extends Node2D
class_name Battle
@onready var enemy := preload("res://Scenes/Enemy.tscn")
@onready var player := preload("res://Scenes/Player.tscn")
var play: Player
signal kill_enemy(del_enemy: Enemy)
func _ready() -> void:
kill_enemy.connect(delete_enemy)
spawn_player()
spawn_enemies()
##Temp function to just spawn 2 zombies, add correct positions and stuff later
##Enemy positions, Holds the enemy object in the corresponding position BUT is a dynamic array that appends so watch out for that
func spawn_enemies():
var zomb1 = enemy.instantiate()
var zomb2 = enemy.instantiate()
zomb1.enemy_stats = preload("res://Resources/Enemy/zombie.tres")
zomb2.enemy_stats = preload("res://Resources/Enemy/zombie_red.tres")
add_child(zomb1)
zomb1.position = Vector2(600, 850)
$EnemySelector.filled_positions.set(0,zomb1)
add_child(zomb2)
zomb2.position = Vector2(1000, 850)
$EnemySelector.filled_positions.set(1,zomb2)
func test():
$BattleDamageCalc.damage_calc(Enums.Type.ZOMBIE, [2,3])
And here’s the relevant child node:
@tool
extends Node2D
class_name Enemy
@export var enemy_stats : EnemyStats
var battle: Battle
var attack_speed = 0.0
func _ready():
if not Engine.is_editor_hint():
enemy_stats = enemy_stats.duplicate(true)
enemy_stats.enemy_health = enemy_stats.enemy_max_health
attack_speed = enemy_stats.enemy_attack_speed
$Sprite2D.texture = enemy_stats.texture
$CharacterBody2D/CollisionShape2D.set_shape(enemy_stats.collision)
##Attack method on a timer, activates based on attack speed (in seconds)
func _process(delta: float) -> void:
if not Engine.is_editor_hint():
attack_speed -= delta
if attack_speed <= 0:
#battle_damage.damage_calc(enemy_stats.type, enemy_stats.enemy_attack)
battle.test()
attack_speed = enemy_stats.enemy_attack_speed
It’s much easier to read if you put ``` on the lines at the top and bottom of your code. That will preserve indentation.
Having said that, some questions:
var parent: Parent line.class_name is Battle, not Parent, and you’re inheriting from a Node2D. So that code is not going to work. Why were you expecting it to?I also recommend changing these lines:
@onready var enemy := preload(“res://Scenes/Enemy.tscn”)
@onready var player := preload(“res://Scenes/Player.tscn”)
To these:
const ENEMY = preload(“res://Scenes/Enemy.tscn”)
const PLAYER = preload(“res://Scenes/Player.tscn”)
Nope I was just literally quoting what you wrote in your first post.
Now that you’ve formatted your code it’s easy to spot the battle variable.
The problem is you never assign a value to battle.
var battle: Battle
This says create a variable named battle of type Battle, and then initializes it to null.
Then you just try to use it. Of course it is null. You said it was null.
Try this instead:
@onready var battle: Battle = get_parent()
You’re totally right, I was so used to exporting the variable and assigning it there, my bad. Another question: Is that the best way to assign parent? Because I’ve heard get_parent() and get_node() should be avoided whenever possible
Did you hear why?
If you’re worried about it the other way might be less processing power would be to have the parent assign it when creating the object. However that could cause all sorts of issues and isn’t great from a design perspective. If you really want to do that I suggest creating an _init() function.
var parent
func _init(parent_node: Node) -> void:
parent = parent_node
This will only work is the Zombie scene itself can be full constructed from the enemy scene.
func spawn_enemies():
var zomb1 = Enemy.new(self)
zomb1.enemy_stats = preload("res://Resources/Enemy/zombie.tres")
add_child(zomb1)
zomb1.position = Vector2(600, 850)
Alternately you could create a setup() function to apply after the fact. But if you forget it, you’ll get an error that may not be super helpful.
All-in-all I’d recommend using get_parent() and not worry about it. My understanding is that get_node() is much processor intensive as it scans the whole tree.
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.