Spawning enemies
This content is not available in your language yet.
Let’s get our enemies spawning on their own, we wouldn’t have much of a game if we had to add every enemy manually!
As you may have come to expect by now, we’ll be making a new scene, again with a Node3D root. Although in this case, that’ll be it! We don’t need our spawner to do anything other than exist in 3D Space with a script. If you want your spawners to be visible, feel free to add a MeshInstance3D but mine will be invisible. Save the scene, call it ‘spawner_scene’
Let’s get straight into the scripting! Attach it to the Node3D in your new scene, call it ‘spawner_script’
-
Let’s again have a think about what we’re going to need:
- A reference to the enemy Scene so we can create copies of it
- Some way to control how often enemies are spawned
- To actually spawn the enemy
Nothing too complicated! But definitely some new concepts. We’ll tackle them one at a time!
-
As always, let’s start by declaring some variables.
@export var spawn_delay_lower = 2@export var spawn_delay_upper = 4@export var enemy_scene:PackedScenevar ready_to_spawn = trueWe won’t be doing anything in the _ready() function so you can either delete it or just leave it.
Our first two exported variables here will be used to control the spawnrate of our enemies, while allowing for some randomness. Our second export will be our reference to our enemy. When we declare a variable in Godot, we can add ’:” followed by a variable type to allow only that type. This is especially useful for exports. (If not declaring a default value, exports require a type to be given)
ready_to_spawn is simply to keep track of if we’re ready to spawn another enemy yet.
-
Let’s get straight into the _process function!
First things first, let’s check if we’re ready to spawn another enemy.
if(ready_to_spawn):ready_to_spawn = falsevar rng = RandomNumberGenerator.new()simple enough, if we are ready to spawn, indicate that we’re not ready to spawn, and go onto our spawning logic. We’ll also create a new RandomNumberGenerator so that we can generate a random number within our defined range.
-
Next, we’ll need to create a Timer and create our very own Signal that calls a function when the timer ends. Sounds scary, but I promise it’s not!
First, let’s make that Timer
var t = get_tree().create_timer(rng.randi_range(spawn_delay_lower, spawn_delay_upper))This will create a timer, add it to the scene tree (Everything needs to be in the tree) and give it a timer with a length between our lower and upper spawn_delay
-
Now, let’s connect it to a function.
t.timeout.connect(spawnEnemy)You’ve made your very own signal like the one we used earlier! This connects our as of yet uncreated function called ‘spawnenemy’ when the timer ends.
-
Giving us a process function that looks like this:
func _process(delta):if(ready_to_spawn):ready_to_spawn = falsevar rng = RandomNumberGenerator.new()var t = get_tree().create_timer(rng.randi_range(spawn_delay_lower, spawn_delay_upper))t.timeout.connect(spawnEnemy) -
Let’s make that function, where our actual spawning logic will sit.
First, we need to instantiate (create) an instance of our enemy scene
func spawnEnemy():var n = enemy_scene.instantiate()add_child(n)We create a copy of the node, and importantly, add it to the scene.
-
Then, let’s set its position, and then flag that we’re ready to create a new enemy
n.global_position = global_positionready_to_spawn = true -
giving us a function that looks like this:
func spawnEnemy():var n = enemy_scene.instantiate()add_child(n)n.global_position = global_positionready_to_spawn = true
Our script is done, but there are a couple more important things we need to do before it’s ready to test.
- Make sure you open the spawner scene and in the inspector drag your enemy scene into the ‘enemy_scene’ field.
- Move your spawner from the scene origin to somewhere else in the scene, so that it doesn’t spawn things on top of the objective.
After those steps, we should be good to test! Run your game, and let a few enemies spawn.
Congratulations! Your game now has continuously spawning enemies! Now to destroy them!
Some things to try
Section titled Some things to try- Trying messing with the spawn timer variables until you’re happy with their rate of spawning.
- Add a few more spawners to your scene, so that enemies spawn from multiple different locations
- If you created a second type of enemy, create spawners that create that enemy with a different spawn delay Remember: You don’t need to make a new script, all you need to do is change the scene inside the ‘enemy_scene’ field!