Game Dev Artisan Logo
In this post we’re going to continue our series on Godot Fundamentals. We’ll be improving our collision detection as well as adding interaction with our Tank and Bullets, by creating some additional interact-able objects such as a crate, pickups, and walls to collide into.
Tutorials

Collisions - Layers, Detections, and Interactions: Godot Fundamentals

In Series: Godot Fundamentals

Author Avatar
2023-06-21
7 min read

Table of Contents

Introduction 

In this post we’re going to continue our series on Godot Fundamentals. We’ll be improving our collision detection as well as adding interaction with our Tank and Bullets, by creating some additional interact-able objects such as a crate, pickups, and walls to collide into.

Video 

You can watch the video covering this topic, or go at your own pace following this post.

Collision Inspector Settings 

If we open our Tank scene and select the root node, we can see the Inspector panel contains a section called Collision and this contains the Collision's Layer and Mask bitmask toggles. From here you can define the Layer that your Node belongs to, and the Mask describes on which layer you are going to scan for collisions to occur on.

To customize the Layer names, you can select the elipses and select Edit Layer Names or open Project Settings and goto Layer Names > 2D Physics. From here you can give each Layer a name that best describes what will belong to it.

Setup Tank Collisions 

For our Tank's collisions, it'll belong to our Player Layer and will Mask to check for collisions against the World Layer, which is where our Walls belong.

Setup Bullet Collisions 

For our bullet's collisions, we'll set it up to belong to the Weapons Layer and we'll Mask it to look for collisions on the World, Destructables, and Enemies Layers.

Sprites 

We've created sprites for our Crate, Walls, and Pickups. You may create your own, or you can download them from the projects github page . Once you've created or download those assets, ensure they are inside your res://assets/sprites/ folder.

Crate Scene 

Let's create our Crate scene with our root using the RigidBody2D node. We'll add a Sprite2D node and set the texture to our Crate sprite asset. We'll also add a CollisionShape2D node and set it's shape to a RectangleShape2D. Resize the shape to fit the Crate asset.

Set the Collision Layer to the Destructables layer and our Mask to the Player, World, *Destructables, and Weapons layers. We'll save this scene as crate.tscn in the res://scenes/ folder and attach a script called crate.gd as well.

We'll confirm that the Crate script has a class_name Crate. We'll also confirm res://scenes/tank.gd has class_name Tank and res://scenes/bullet.gd has class_name Bullet.

Wall Scene 

Next we'll create the Wall Scene using the *StaticBody2D. We'll add a Sprite2D node and set the texture to our Wall sprite asset. We'll also add a CollisionShape2D node and set it's shape to a RectangleShape2D. Resize the shape to fit our Wall asset.

Pickup Scene 

For our Pickup Scene, we'll start with an Area2D. Add our Sprite2D node, set the texture to the Pickup asset. Add the CollisionShape2D node and add the shape as a RectangleShape2D. Resize the shape to fit our Pickup asset.

We'll add a Pickup script called pickup.gd, and add the class_name Pickup to the script.

TileMap for Walls and Crates 

We'll use Godot 4's new feature with TileMaps to allow us to add our Wall and Crate scenes within a grid in our World scene. Open up the World scene and add a TileMap node and in the inspector we'll create a new TileSet. Inside the TileSet panel at the bottom we'll add a new TileSet source of type Scene Collection and we'll name it walls. From there we'll add the wall scene as the tile source. We'll create another tile for the destructables and drag over the crate scene.

Under the Inspector panel for the TileMap, under the Layers section, we'll name our first layer walls and create a second layer named destructables. Once we have separate layers, we can select the TileMap tab on the bottom panel and start paining on our walls and destructables layers, by toggling the dropdown on the right.

Gravity Setup 

When running our game, the crates will drop out of our view because they are RigidBody2D type nodes, which by default are affected by gravity. You can modify the default behavior of gravity through Project Settings under the Physics > 2D and set the Default Gravity Vector to be 0 on the x and y.

This will prevent gravity from pulling the objects out of the scene.

Linear and Angular Dampening 

Another issue we'll notice is that our crates will continue to move along their path when they are collided with and won't come to a stop. We can solve this by adding dampening to the linear and angular forces of our Crate scene. If we add linear velocity of (1,1) and a damp of 100, and 100 on the angular damp, our crates should now no longer slide when a collision occurs. Adjust the damp to better fit the collision you'd like.

Bullet Interactions 

Next we will add interactions to occur on our Bullet when a collides with other objects. If we open our Bullet scene and corresponding script, we can select the Area2D root node and open the Node tab of the Inspector Panel. From here we can see the list of Signals that are available for the Area2D node.

We'll connect the body_entered signal to our script and define our _on_body_entered function that will check if the Bullet collides with Crate body and call body.destroy() to destroy the crate instance and in all cases, queue_free() to remove the instance.

Inside our Crate script, we'll define the destroy function to also queue_free() and remove the instance of the crate.

Pickup Instances 

When a Crate is destroyed, we'll also want to create an instance of our Pickup. To do this we'll add @export var PICKUP_SCENE: PackedScene to allow us to set the Pickup Scene as a variable. In our destroy function of our Crate, we'll create an instance of the Pickup Scene by calling instantiate() on our PICKUP_SCENE and setting it to our var pickup variable. After that we can set the pickup's global_position and add it as a child to the parent's SceneTree.

From our Pickup scene, we'll connect the body_entered signal to our _on_body_entered function within the pickup script. Inside this function we'll check that the body is of type Tank and if so, we'll queue_free() our pickup instance.

Recap 

We've now created the necessary collisions and interactions to move around, stop movement on walls, push and destroy crates, create pickups, and pickup those with our Tank. If you have any issues, jump in the discord community and join in the discussions.

We'll see you in the next one!

Happy Coding.

Want to support our work?Support us via Ko-fi