Godot Version
4.2
Question
I’m trying to spawn a fireball every 3 second. But if the player level up, it will shoot 2 fireball instead. I did that with the await code but I heard that it is not a good practice.
func shoot_fireball(times_to_shoot: int = 1):
for i in range(times_to_shoot):
var new_fireball = FIRE_BALL.instantiate()
new_fireball.global_position = %shooting_fireball_point.global_position
%shooting_fireball_point.add_child(new_fireball)
$fireBall.play()
await get_tree().create_timer(0.2).timeout
func _on_fireball_timer_timeout():
if fireball1:
shoot_fireball(1)
if fireball2:
shoot_fireball(2)
if fireball3:
shoot_fireball(3)
so I modify my code but now it only shoot 1 all the time instead.
func shoot_fireball():
var new_fireball = FIRE_BALL.instantiate()
new_fireball.global_position = %shooting_fireball_point.global_position
%shooting_fireball_point.add_child(new_fireball)
$fireBall.play()
$fireball_between_timer.start()
func _on_fireball_timer_timeout():
if fireball1 and $fireball_between_timer.is_stopped():
shoot_fireball()
if fireball2 and $fireball_between_timer.is_stopped():
for i in range(2):
shoot_fireball()
if fireball3 and $fireball_between_timer.is_stopped():
for i in range(2):
shoot_fireball()
how to fix this?
I think I need more context to understand your problem.
What do you mean by
But if the player level up, it will shoot 2 fireball instead.
Also, what is fireball1
, fireball2
, and fireball3
and how are they set in your code?
I’ve created a minimal project to try to reproduce your issue, but I’m not seeing a problem of only shooting once. Here’s how I structured mine:

fireball_spawner.gd
extends Node2D
@export var fireball : PackedScene
func _on_shoot_timer_timeout() -> void:
var rng = RandomNumberGenerator.new()
var num = rng.randi_range(1,3)
print(num)
shoot_fireball(num)
func shoot_fireball(times_to_shoot : int):
for i in range(times_to_shoot):
var new_fireball = fireball.instantiate()
new_fireball.global_position = %ShootingPoint.global_position
%ShootingPoint.add_child(new_fireball)
%ShootTimer.start()

fireball.gd
extends Node2D
var y_dir
var rng = RandomNumberGenerator.new()
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
y_dir = rng.randf_range(-45.0,45.0)
print(y_dir)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
position.x += 300 * delta
position.y += y_dir * delta
And here’s my output.
Thank you, GodofGrunts, for taking the time to answer my question. I’m new to Godot, but I’ll do my best to follow your code. In the meantime, I’ll provide more context.
This is my fireball.gd code
extends Area2D
var travelled_distance = 0
var target_enemy = null
const SPEED = 150
const RANGE = 1000
func _process(delta):
var direction = Vector2.RIGHT.rotated(rotation)
position += direction * SPEED * delta
# If there is a target enemy, home towards it
if target_enemy and target_enemy != null:
look_at(target_enemy.global_position)
#else:
#target_enemy = find_closest_enemy()
travelled_distance += SPEED * delta
if travelled_distance > RANGE:
queue_free()
func _ready():
target_enemy = find_closest_enemy()
func find_closest_enemy():
var enemies = get_tree().get_nodes_in_group('Enemies')
var closest_enemy = null
var min_distance = INF
for enemy in enemies:
var distance = global_position.distance_squared_to(enemy.global_position)
if distance < min_distance:
min_distance = distance
closest_enemy = enemy
return closest_enemy
func _on_body_entered(body):
queue_free()
if body.has_method("take_damage"):
body.take_damage(1)
Nothing special, I tried to implement the steering homing fireball, but it doesn’t work, so I’ve left it as is for now. Below is my player.gd script that I use for fireball spawning.
extends CharacterBody2D
#fireball
const FIRE_BALL = preload("res://scenes/fire_ball.tscn")
var fireball1: bool = false
var fireball2: bool = false
var fireball3: bool = false
var fireball4: bool = false
var fireball5: bool = false
func shoot_fireball(times_to_shoot: int = 1):
for i in range(times_to_shoot):
var new_fireball = FIRE_BALL.instantiate()
new_fireball.global_position = %shooting_fireball_point.global_position
%shooting_fireball_point.add_child(new_fireball)
$fireBall.play()
await get_tree().create_timer(0.2).timeout
func _on_fireball_timer_timeout():
if fireball1:
shoot_fireball(1)
if fireball2:
shoot_fireball(2)
if fireball3:
shoot_fireball(3)
if fireball4:
shoot_fireball(4)
if fireball5:
shoot_fireball(5)
func update_exp(amount: int):
$expCollect.play()
currentExp += amount
if currentExp >= maxExp:
$levelUp.play()
currentExp = 0
maxExp += 5
print("lvl up")
levelUp.emit()
expChanged.emit()
After the player levels up and chooses to pick the fireball skill again, fireball2 will be set to true. The function will then shoot 2 fireballs instead of just 1 when the fireball timer times out. (I’ve set the fireball timer to 3 seconds, so it will automatically fire fireballs every 3 seconds). I’ve set the fireball_between_timer to 0.5 because I believe the issue lies in the for loop. It may be spawning 2 or 3 fireballs at the same time, causing only one fireball to be visible in the game.