Learn Godot 4 by Making a 2D Platformer — Part 8: Bomb Spawner
Tags: gamedev, beginners, tutorial, programming
Published: 2023-07-25 03:01:00

**You can find the links to the previous parts at the bottom of this tutorial.*

We now have a bomb in our game, but we still need a spawner for it. The spawner will spawn the bomb on a certain path — and it will respawn a new bomb each time the bomb collides with the player or with the wall/tilemap. Instead of placing the bomb down on the maps ourselves, the spawner will take care of it for us.

---

***WHAT YOU WILL LEARN IN THIS PART:***

* *How to work with Path2D nodes.*
* *How to work with PathFollow2D nodes.*
* *How to work with AnimationPlayer nodes.*

---


We will be creating a pre-defined path for our bomb using the [Path2D ](https://docs.godotengine.org/en/stable/classes/class_path2d.html#class-path2d)node. This Path2D node allows us to draw points on the map which will serve as our bomb path. After we’ve created our path points, we will use the [PathFollow2D](https://docs.godotengine.org/en/stable/classes/class_pathfollow2d.html) node to move our spawned Bomb scene along this path. We will need to use the [AnimationPlayer](https://docs.godotengine.org/en/stable/classes/class_animationplayer.html) node to animate our bomb’s movement as it follows this path.

Let’s create a new scene for our Bomb Spawner! Our root node should be a Node2D node — which you can rename as “BombSpawner”. Save this scene under your Scenes folder.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2190/1*OdPbihtErjkO4YHSCG5bzQ.png)

This BombSpawner scene will need a Timer node, which will spawn a bomb each time the bomb count falls below zero (if there are no bombs, the timer will spawn a new one).

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*RKCwvoYzk3bF3ol_SSEgJQ.png)

In the Timer node’s Inspector panel, we need to enable the “Autostart” option. This will start the timer automatically when the BombSpawner enters the Main scene tree. The other option “one-shot” fire off the timer once, and the timer will stop when reaching 0.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*Ru725LxG74gQaXFGoNBCZg.png)

Finally, this scene will need an AnimatedSprite2D node. This AnimatedSprite2D node will contain the animations for our cannon which will shoot the bomb. We will add the cannon handler in the next part!

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*_JRgHJAiDc3ZHpBa_zFoJw.png)

Let’s create two new animations for our cannon called “cannon_idle” and “cannon_fired”.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*cdkx4pDsJVJh1RXotnl_rg.png)

For our *cannon_idle* animation, navigate to “res://Assets/Kings and Pigs/Sprites/10-Cannon/Idle.png” and add the only frame to your animation. Leave the looping and FPS values as the default values for now.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2474/1*aj-57jrZ2GQ3-p78mo0F3Q.png)

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*FGfkYG7qX3NnjgYfODIcHw.png)

For our *cannon_fired* animation, navigate to “res://Assets/Kings and Pigs/Sprites/10-Cannon/Shoot (44x28).png” and add all 4 frames to your animation. Add the first frame twice, so that the cannon animation starts and ends with the same frame. Turn the looping off, and leave change its FPS value to 4.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2486/1*auxYaiNHoo6BkJ_Ja8-k0w.png)

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2076/1*8RAt2aK2yC4M9J4i0GpTTg.png)

We also want our cannon to face the other way (right), so in the AnimatedSprite2D node’s Inspector panel, underneath Offset, enable the “Flip H” property.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2918/1*fnsTyl-VBxHffgDD0yjTog.png)

We’ll come back to our BombSpawner scene in a minute, but for now, let’s head back to our Main scene and add a new Node2D node to our scene. Rename it to “BombPath”. Also, delete any Bomb scene that you’ve previously instanced from your scene.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*PXZXj1ZO2tAebkaR5uHFqA.png)

Add a [Path2D](https://docs.godotengine.org/en/stable/classes/class_path2d.html#class-path2d) node as a child of the BombPath node. This node will allow us to draw path points for our bomb’s movement.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2700/1*aUZp1aSiKjdSPSuW9EOaVg.png)

If you select your Path2D node, you will see in the Inspector panel that there is an option to add Points. If you add an element to the Points property, you will see that it created a diamond shape on your game window at (x: 0, y: 0).

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*VHUUSsRtAPEsro_idhZTjg.png)

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/3824/1*YiHC8Rv7RAMw7pN5k4Tu6Q.png)

You can drag this point anywhere on your map where you want your bomb to spawn. This is the starting point of your bomb path. You can move it around later on.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/3312/1*kGSkqXaXDGcVkniemScZdw.png)

If you add another element, it will create another point.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/3322/1*gA-KI4l1y4JaWmrByJ3qGw.png)

You can also click on the line now to add points, and if you want to move points you can simply select them and drag them to where you want to place them. To delete a point, you can right-click on it with your mouse or delete it in your Inspector panel.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/3304/1*pnge6c_1L4U5TCPlW2G_1g.png)

Let’s create a path from the top to the bottom for our bomb. The bomb will follow this path each time it spawns, and if it reaches the end of this path or collides with our player, it will respawn from the top and make its way down to the end again. Make sure that you leave enough space for your player to be able to jump over the bomb, and if you made your bomb collide with your Tilemap (option #1) — ensure that you have enough space for your bomb to flow without exploding.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2326/1*1PpLDqGDpGbQPRmg1ERlSw.png)

For our bomb to follow this path after it has been spawned on it, we need to add a PathFollow2D node as a child of the Path2D node.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2316/1*OUpt-0csArhNWzVryM8GoQ.png)

We also need to add an AnimationPlayer node as a child of the Path2D node. An animation player is used for general-purpose playback of [Animation](https://docs.godotengine.org/en/stable/classes/class_animation.html#class-animation) resources. It contains a dictionary of [AnimationLibrary](https://docs.godotengine.org/en/stable/classes/class_animationlibrary.html#class-animationlibrary) resources and custom blend times between animation transitions. You will use this AnimationPlayer node whenever you need to animate non-sprite items, such as labels or colors.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2054/1*j9sfKeb3GHAilAmmoGUJAA.png)

We add animations to the AnimationPlayer node in the Animation panel below.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2330/1*GQsOXJiIXh_fTZ9gfSLXhg.png)

To add a new Animation, click on the Animation property and select the option “New”. Call this animation “bomb_movement”.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*ht_8vudfFpEDInJjzwkg0w.png)

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*l4ChdxWC_BeEx9VQuYplow.png)

**This will create an animation consisting of four parts:**

* The controls (i.e. add, load, save, and delete animations)

* The tracks listing.

* The timeline with keyframes — which defines the value of a property at a point in time.

* The timeline and track controls, where you can zoom the timeline and edit tracks, for example. You can also zoom in and out on the timeline by holding down CRTL and scrolling with your mouse wheel.

![Figure 9: Animation Panel Overview](https://cdn-images-1.medium.com/max/2000/1*ZyVsF80MTFIbuSeE2_AOyA.png)

Let’s change our animation length to 5. This will be the time it takes for our bomb to move from the first point on our Path2D node to the last point. We can change this later to make it slower or faster.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2330/1*wN23izr51ZUXSGm7aYlrcA.png)

Let’s create a new Track. Each track stores a path to a node and its affected property. Click on “Add Track” and select “Property Track”. We are choosing Property Track because we want to change the property value of a certain node (properties that we can find in the Inspector panel).

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*YVRcNHRfvfddd84m0Y4OwQ.png)

We want to animate the property of the progress ratio of our PathFollow2D node so that we can move the Bomb across the path according to that progress ratio. Since we want to animate the PathFollow2D node, we need to select it in the popup window that arises.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*2MlncqbtD9LvqC0Abm1g5g.png)

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*0qugdeuOHCsu_QayxzC2IA.png)

We can now select the property of the PathFollow2D node that we want to animate. Select “progress ratio”. This progress ratio refers to the distance along the path as a number in the range of 0.0 (for the first vertex) to 1.0 (for the last). This is just another way of expressing the progress within the path, as the offset supplied is multiplied internally by the path’s length.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2308/1*Pe84HDSjz3wJcuk2aFZKnw.png)

Let’s add two keyframes: one at the start and one at the end of the animation timeline. To add a new keyframe, right-click on your mouse and select “Insert Key”. Add a key at point 0 and point 5 on your timeline. 0 is our start location, where the bomb will spawn and start moving, and 5 is the end location, where the bomb will be destroyed and stop moving.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2314/1*dANjZv5O5ATQRJRN2GT8hQ.png)

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/3326/1*cK7bnUizUmb35NU0cLEpHQ.png)

Right now the animation won’t move because the progress ratio is moving from value 0 to value 0. If you select your keyframe, you can see this value in the Inspector panel. We need to change the Value property of our keyframe “5” to 1. This means our animation will play from 0 to 1, so our bomb will move along the path and not just stay stuck in place. Select the keyframe that you placed on time 5 and change its value to 1. We can’t test this animation yet, but we need it or else our Bomb won’t move on our path!

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/3326/1*cK7bnUizUmb35NU0cLEpHQ.png)

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/3356/1*URl0hkGtoC40O-SiQN0j5g.png)

Redo the same steps as above (for our BombPath) for your second level in your Main_2 scene.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2816/1*9NnzaU68FZraUkLvthhixA.png)

Now, back in our BombSpawner scene, we need to add a new script to our scene. Save it in your Scripts folder.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*Dr5NE3LROEta3PoC5JkXjw.png)

In our newly created script, we need to define a few variables. First, we’ll need to create a reference to our Bomb scene. We can do this via the global [preload](https://docs.godotengine.org/en/stable/classes/class_%40gdscript.html#class-gdscript-method-preload) method, which loads our Scene resource as early as possible to front-load the “loading” operations and avoid loading resources while in the middle of performance-sensitive code. Preloading makes sure that the scene is loaded into memory before the game starts, which can help to avoid delays later.
```python
    ### BombSpawner.gd
    
    extends Node2D
    
    #bomb scene reference
    var bomb = preload("res://Scenes/Bomb.tscn")
```
Since we have more than one level we’ll need to find a way to dynamically change the name of the current scene so that we can get its path accordingly. In other words, if we are in our Main scene, we want our bomb to spawn on our *“/root/Main/BombPath/Path2D/PathFollow2D”* path, and if we are in our Main_2 scene, we want our bomb to spawn on our *“/root/Main_2/BombPath/Path2D/PathFollow2D”* path.

We can use our Global script to keep track of which main scene is currently active. We’ll use our *ready()* function to get the name of the current scene that our Player is in (Main or Main_2). We’ll do this via the [current_scene()](https://docs.godotengine.org/en/stable/classes/class_scenetree.html#class-scenetree-property-current-scene) object.
```python
    ### Global.gd
    
    extends Node
    
    #movement states
    var is_attacking = false
    var is_climbing = false
    var is_jumping = false
    
    #current scene
    var current_scene_name
    
    func _ready():
        # Sets the current scene's name
        current_scene_name = get_tree().get_current_scene().name
```
Now, back in our BombSpawner script let’s define some variables that will store our *current_scene_path* value (Main or Main_2), our bomb path (current_scene_path + /BombPath/Path2D/PathFollow2D), and our bomb animation path (current_scene_path + /BombPath/Path2D/AnimationPlayer).
```python
    ### Bombspawner.gd
    
    extends Node2D
    
    #Bomb scene reference
    var bomb = preload("res://Scenes/Bomb.tscn")
    
    #references to our scene, PathFollow2D path, and AnimationPlayer path
    var current_scene_path
    var bomb_path
    var bomb_animation
```
We will initiate the values of these variables in our *ready()* function. We also need to set the default load animation of our cannon to “cannon_idle”.
```python
    ### Bombspawner.gd
    
    #older code
    
    #when it's loaded into the scene
    func _ready():
        #default animation on load
        $AnimatedSprite2D.play("cannon_idle")   
        #initiates paths
        current_scene_path = "/root/" + Global.current_scene_name + "/" #current scene
        bomb_path = get_node(current_scene_path + "/BombPath/Path2D/PathFollow2D") #PathFollow2D
        bomb_animation = get_node(current_scene_path + "/BombPath/Path2D/AnimationPlayer") #AnimationPlayer
```
To spawn our bomb we’ll need to create a new function that will create an instance of the bomb scene and return it. To create an instance of our scene reference we use the [instantiate()](https://docs.godotengine.org/en/stable/classes/class_packedscene.html#class-packedscene-method-instantiate) method. We also need to play our *cannon_fired* animation, which will play each time our function is called to spawn a new bomb.
```python
    ### Bombspawner.gd
    
    #older code
    
    #spawns bomb instance    
    func shoot():
        #play cannon shoot animation each time the function is fired off
        $AnimatedSprite2D.play("cannon_fired")
        #returns spawned bomb
        var spawned_bomb = bomb.instantiate()
        return spawned_bomb
```
To spawn a bomb via our shoot function, we’ll need to connect our Timer node’s *timeout()* signal to our script.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*oCO1do1XeQK7gkrrBMsgyw.png)

In the *_on_timer_timeout()* function we need to check if there are no bombs currently spawned on our scene, and if it is true, we will call our *shoot()* function and spawn a bomb onto our *bomb_path*. We can check the children of our “/BombPath/Path2D/PathFollow2D/” node via the [get_child](https://docs.godotengine.org/en/stable/classes/class_node.html#class-node-method-get-child-count) or [get_child_count](https://docs.godotengine.org/en/stable/classes/class_node.html#class-node-method-get-child-count) methods. You can add a node to a defined path (such as our bomb_path) by using the [add_child](https://docs.godotengine.org/en/stable/classes/class_node.html#class-node-method-add-child) method. This will create a Bomb under our path, so our path will end up looking like “/BombPath/Path2D/PathFollow2D/Bomb”.
```python
    ### Bombspawner.gd
    
    #older code
    
    #shoot and spawn bomb onto path
    func _on_timer_timeout():
        #reset animation before shooting    
        $AnimatedSprite2D.play("cannon_idle")
        #spawns a bomb onto our path if there are no bombs available
        if bomb_path.get_child_count() <= 0:
            bomb_path.add_child(shoot())
```
Finally, we need to check the path for any changes. If the bomb has reached the end of the path (when the animation reaches the 1 value), we need to reset the path value back to 0 so that the animation can restart, as well as spawn a new bomb.

For this to work properly, we need to create a Global variable that will change the state of our bomb movement. If our bomb is spawned, it should be moving, and if it collides with our player, it should not be moving.
```python
    ### Global.gd
    
    extends Node
    
    #movement states
    var is_attacking = false
    var is_climbing = false
    var is_jumping = false
    
    #current scene
    var current_scene_name
    
    #bomb movement state
    var is_bomb_moving = false
    
    func _ready():
        # Sets the current scene's name
        current_scene_name = get_tree().get_current_scene().name
```
```python
    ### Bomb.gd
    
    #older code
    
    func _on_body_entered(body):
        #if the bomb collides with the player, play the explosion animation and start the timer
        if body.name == "Player":
            $AnimatedSprite2D.play("explode")
            $Timer.start()
            Global.is_bomb_moving = false
        #OPTION 1   
        #if the bomb collides with our Level Tilemap (floor and walls). 
        if body.name == "Level" and !body.name.begins_with("Platform"):
            $AnimatedSprite2D.play("explode")
            $Timer.start()
            Global.is_bomb_moving = false
            
        #OPTION 2   
        #if the bomb collides with our Wall scene, explode and remove
        if body.name.begins_with("Wall"):
            $AnimatedSprite2D.play("explode")
            $Timer.start()
            Global.is_bomb_moving = false
```
```python
    ### BombSpawner.gd
    
    #older code
    
    #spawns bomb instance    
    func shoot():
        #play cannon shoot animation each time the function is fired off
        $AnimatedSprite2D.play("cannon_fired")
        #sets the bomb to moving and plays bomb animation
        Global.is_bomb_moving = true
        bomb_animation.play("bomb_movement")
        #returns spawned bomb
        var spawned_bomb = bomb.instantiate()
        return spawned_bomb
```
Now, in our *_on_timer_timeout()* function, we can check if our bomb is not moving and if true we need to remove all of our bombs and stop our animation from playing so that our progress ratio can reset back to 0. We can do this by running a [For Loop](https://gdscript.com/tutorials/looping/) which will count the children inside our *bomb_path*, and then remove them all if any exist.
```python
    ### BombSpawner.gd
    
    #older code
    
    #shoot and spawn bomb onto path
    func _on_timer_timeout():
        #reset animation before shooting    
        $AnimatedSprite2D.play("cannon_idle")
        #spawns a bomb onto our path if there are no bombs available
        if bomb_path.get_child_count() <= 0:
            bomb_path.add_child(shoot())
        # Clear all existing bombs  
        if Global.is_bomb_moving == false:
            for bombs in bomb_path.get_children():
                bomb_path.remove_child(bombs)
                bombs.queue_free()
                bomb_animation.stop()
```
Finally, we need our AnimationPlayer from our level scenes to play our *bomb_movement* animation at the start. This will allow the bomb to move when our BombSpawner enters the scene.
```python
    ### Bombspawner.gd
    
    #older code
    
    #when it's loaded into the scene
    func _ready():
        #default animation on load
        $AnimatedSprite2D.play("cannon_idle")   
        #initiates paths
        current_scene_path = "/root/" + Global.current_scene_name + "/" #current scene
        bomb_path = get_node(current_scene_path + "/BombPath/Path2D/PathFollow2D") #PathFollow2D
        bomb_animation = get_node(current_scene_path + "/BombPath/Path2D/AnimationPlayer") #AnimationPlayer
        
        #starts bomb movement
        bomb_animation.play("bomb_movement")
```
Now, in your Main scenes, instance your BombSpawner scene. You want to place your cannon in front of your bomb path.

**Main.tscn:**

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2808/1*sNrF-WvOFAZD2MmT3eT2hw.png)

**Main_2.tscn:**

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2810/1*7bcH9cIn0hRfGbxC2mb1wQ.png)

Now if you run your scene, your bomb should spawn, and if it explodes along the path it should respawn. The bomb is moving a bit too fast, so let’s change the *bomb_movement* animation in our Main scene’s length to be a little higher. You’ll have to test this value out depending on the length of your path.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/3840/1*NbMDSTuG3WXu7d5tvQVoNw.png)

**Main.tscn:**

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2820/1*qZX7jTapjLfQBWSke-zEnw.png)

**Main_2.tscn:**

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2838/1*Vpu7vFqwoptiPbyQVzSz4g.png)

If you notice that your player keeps colliding with the bomb (i.e., they can’t jump over it), consider changing your player’s *jump_height* variable to a value that’s a little lower such as -110. You can also change your Bomb node’s collision shape to be slightly smaller. You can also do the same for your Player’s collision shape.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2832/1*88HqvRM5ay_DacvhURokdg.png)

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2828/1*ER1q-j64N1nxYA0LXCUTNA.png)

Let’s do one last thing for this part. Let’s make the Bomb roll if it is moving. We can do this by adding to its rotate value in the *physics_process()* function. In your Bomb script, create a new variable and set its speed to the speed at which you want your bomb to rotate.
```python
    ### Bomb.gd 
    
    extends Area2D
    
    var rotation_speed = 10
```
Then, in your *physics_process()* function, let’s rotate the bomb if it is moving.

```python    
### Bomb.gd 
    
    #older code
    
    #rolls the bomb
    func _physics_process(delta):
        # Rotate the bomb if it hasn't exploded
        if Global.is_bomb_moving == true:
            $AnimatedSprite2D.rotation += rotation_speed * delta
```
Your code should look like [this](https://github.com/christinec-dev/CastleClimbersParts/tree/main/Part8/Scripts).

Now if you run your scenes, your bomb should roll to the endpoint. If it collides with the colliders that you defined in your Bomb script, it should remove itself from the scene and the spawner should respawn a new bomb. Your player should also be able to jump over the bomb. There is a little spawn delay when the cannon first fires off when the game starts, but it isn’t deal-breaking.

Congratulations on creating your bomb spawner! In the next part, we will create a cannon handler that will have a speech bubble in which it will taunt us — other than that its purpose in our game is purely for visuals!

Now would be a good time to save your project and make a backup of your project so that you can revert to this part if any game-breaking errors occur. Go back and revise what you’ve learned before you continue with the series, and once you’re ready, I’ll see you in the next part!

---

## Next Part to the Tutorial Series

The tutorial series has 24 chapters. I’ll be posting all of the chapters in sectional daily parts over the next couple of weeks. You can find the updated list of the tutorial links for all 24 parts of this series on my [GitBook](https://oops-i-devd.gitbook.io/christinedevs/godot-tutorials/castle-climbers/tutorial). If you don’t see a link added to a part yet, then that means that it hasn’t been posted yet. Also, if there are any future [updates ](https://oops-i-devd.gitbook.io/christinedevs/communication/updates-and-notifications)to the series, my GitBook would be the place where you can keep up-to-date with everything!

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/0*TLFhoNqnjMYLWAGA.png)

---

## Support the Series & Gain Early Access!

If you like this series and would like to support me, you could [donate](https://ko-fi.com/christinedevs) any amount to my KoFi shop or you could [purchase the offline PDF](https://ko-fi.com/s/75433f1d4b) that has the entire series in one on-the-go booklet!

The booklet gives you lifelong access to the full, offline version of the “**Learn Godot 4 by Making a 2D Platformer**” PDF booklet. This is a 451-page document that contains all the tutorials of this series in a sequenced format, plus you get dedicated help from me if you ever get stuck or need advice. This means you don’t have to wait for me to release the next part of the tutorial series on Dev.to or Medium. You can just move on and continue the tutorial at your own pace — anytime and anywhere!

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/0*S6n1i41QDrVlLJUy.png)

*This book will be updated continuously to fix newly discovered bugs, or to fix compatibility issues with newer versions of Godot 4.*