I have a Node2D, a Shooter node that spawns projectiles based on a timer. Basically, it goeth
@export var time_between_shots:float
@export var projectile:PackedScene
@export var projectile_disappear_time:float
@onready var spawn_point:Marker2D = $SpawnPoint
@onready var shoot_timer:Timer = $ShootTimer
@onready var projectile_velocity:Vector2 = spawn_point.global_position - global_position
func _ready():
shoot_timer.wait_time = time_between_shots
shoot_timer.timeout.connect(shoot)
shoot_timer.start()
func shoot():
var inst:Projectile = projectile.instantiate()
owner.add_child(inst)
inst.transform = spawn_point.global_transform
inst.proj_velocity = projectile_velocity
inst.disappear_time = projectile_disappear_time
It spawns projectiles, basically, and sets their speed to a speed based off of another node… Here is the projectile code:
extends Area2D
class_name Projectile
var proj_velocity:Vector2
var disappear_time:float
@onready var bye_timer:Timer = $ByeTimer
func _ready():
bye_timer.wait_time = disappear_time
bye_timer.timeout.connect(func(): queue_free())
bye_timer.start()
func _physics_process(delta:float) -> void:
position += proj_velocity
Here’s the problem: The wait_time isn’t set correctly, which is extra weird because the proj_velocity variable gets set with ease.
I checked, and upon using print(inst.disappear_time) on the Shooter node, it gives the correct time (say, 2.5 seconds), but doing the same print(disappear_time) reveals that it was set to 1.0 automatically. This has had me stumped for a day.
owner is an odd pick here, it might lead to unexpected parents, try add_sibling or setting an explicit node through an @export var project_parent: Node value
@syntaxerror247 is right that you need to call add_child later, _ready() is called at the same time as add_child.
If owner is likely to lead to unexpected parents, what less risky uses are there for it? In the case of the game I’m making, I’m only ever expecting the owner to be the Current Scene, or maybe a Node2D to contain all Shooters
Seems like you have a firm grasp on owner, I’d still call it an odd pick, but I see some getting tricked by it thinking it’s the same as get_parent(). The less risky option would be add_sibling or picking a node through @export
Got it. Also, you seem knowledgeable, I might as well ask:
Why didn’t inst.proj_velocity = projectile_velocity cause the same issue? Is it because it’s a Class, a Vector2D, instead of a basic type, and those do things differently?
The problem is only the order of events. I’ll put your original sample in-order
### starting in: func shoot():
var inst:Projectile = projectile.instantiate()
owner.add_child(inst)
### `add_child` calls func _ready():
# disappear_time has not been set yet!
bye_timer.wait_time = disappear_time
bye_timer.timeout.connect(func(): queue_free())
bye_timer.start()
### _ready finishs, back to finish up in func _shoot():
inst.transform = spawn_point.global_transform
inst.proj_velocity = projectile_velocity
# finally disappear_time is set, but it's far too late!
inst.disappear_time = projectile_disappear_time
Since proj_velocity is applied every physics process it does not matter when the value is set relative to _ready(), but the timer does care, becase it’s wait_time is only set once on _ready().
Another small nit-pick is you can connect to queue_free directly instead of through a lambda
bye_timer.timeout.connect(queue_free) # no parenthesis