How can I make enemies appear after a specific interval and not all together ?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Scavex

I am working on a game and I have made three different types of enemies and I spawn them using a Spawner. The only issue I have is that when I start my game all of them appear together and then they come randomly. I want one enemy to come first and then after some time second enemy will start appearing and then third and so on. How can I do that ? This is my spawn function

func spawn():
	while true:
		randomize()
		var enemy = enemy1.instance()
		var pos = Vector2()
		pos.x = rand_range(0+16, get_viewport().get_visible_rect().size.x-16)
		pos.y = 0-16
		enemy.set_position(pos)
		get_node("Container").add_child(enemy)
		yield(get_tree().create_timer(rand_range(1.25,3.00)),"timeout")
:bust_in_silhouette: Reply From: njamster

While not obvious from your question, it sounds like you call spawn in _ready. In which case of course all enemies will spawn at the same time first. A simple fix to that should be moving the last line up to the start of the while-loop though:

func spawn():
    while true:
        yield(get_tree().create_timer(rand_range(1.25,3.00)),"timeout")
        randomize()
        var enemy = enemy1.instance()
        var pos = Vector2()
        pos.x = rand_range(0+16, get_viewport().get_visible_rect().size.x-16)
        pos.y = 0-16
        enemy.set_position(pos)
        get_node("Container").add_child(enemy)

Thanks sir it surely makes the enemies appear differently now but I was wondering if I could do something that will make the enemies appear after a long time. For example I want to do something like this, make the first enemy appear when the game starts then make the second enemy appear after 15 seconds or so. I tried using a TIMER but it seems like _ready() ignores the timer and hence my timer isn’t working. here’s the code


func _ready() -> void:
	spawnEnemy1()
	$EnemySpawnTimer.start(20)
	_on_EnemySpawnTimer_timeout()

func spawn():
    	while true:
    		yield(get_tree().create_timer(rand_range(1.25,3.00)),"timeout")
    		randomize()
    		var enemy = enemy1.instance()
    		var pos = Vector2()
    		pos.x = rand_range(0+16, get_viewport().get_visible_rect().size.x-16)
    		pos.y = 0-16
    		enemy.set_position(pos)
    		get_node("Container").add_child(enemy)

func _on_EnemySpawnTimer_timeout() -> void:
	spawnEnemy2()

I also tried making a counter that will count how many enemies I have killed and then spawn the other enemies. For that I added a variable in the global script but in my _ready() if I do something like this :

func _ready() -> void:
	spawnEnemy1()
	if global.enemykillCount > Any value:
		spawnEnemy2()

the if statement never executes for some reason.

Scavex | 2020-09-05 12:25

The _ready()-function is only run once when the scene is loaded! As the condition is not true at that point, spawnEnemy2() won’t executed. If you add your if-statement to _process it will work. However, then the condition is checked each frame! A proper solution would only re-evaluate the condition when enemykillCount changed.

As for the timer: That should work! At least when I assume $EnemySpawnTimer gets the right node and its timeout-signal was connected in the editor (as it isn’t in code!). However, it’s worth pointing out that you call the callback manually right after starting the timer which might have given you the impression that it didn’t work?

njamster | 2020-09-05 13:30

Thanks the timer just worked. I don’t know why it wasn’t working before. I restarted engine and it worked. Than you very much sir

Scavex | 2020-09-05 13:54