Table of Contents
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.
You can watch the video covering this topic, or go at your own pace following this post.
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.
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.
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.
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
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.
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.
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.
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.
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
This will prevent gravity from pulling the objects out of the scene.
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.
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.
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.
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!