Monday 15 May 2017

Gitting Gud At Godot - Part 6 - Intersections and Signals

Watch the video version of this tutorial here:

In this tutorial, we're going to deal with intersections and signals. I'm sorry to let you down, but we're going to have to put off instancing until later since it's actually a lot bigger than I thought. I hope you can forgive me for the most egregious form of deceit.

In Part 5, we briefly covered hard collision, where each physics body just smacks into the others. Now, we're going to deal with intersections.

Sadly, physics bodies like the ones that we know can't detect intersections very well. We need to use a new kind of node called an Area2D.

Create a new Area2D node as a child of the tree root, give it a Sprite and give it a suitable CollisionShape2D. I'm going to name my Area2D node "collectable".

You can now launch your game, and walk into the new Area2D we just created. With any luck, the player just passes right through it! This is where it's going to get interesting.

You might have notice in the Inspector tab area, that there is another tab beside it named "Node". Make sure your Area2D is highlighted and select the "Node" tab. This is where you can bind signals to your nodes.

To put it simply, a signal is emitted whenever the associated thing happens. Whenever a signal is emitted, any functions that you've connected to the signal will be called.

For now, let's connect the "body_enter" signal to our player object. Select the "body_enter" signal under "Area2D" in the Node tab and click the "Connect" button at the bottom. It should open a large dialogue with your nodes listed on the left hand side.

There are a few things to notice here. First of all, your nodes are listed on the left hand side. The node that you're modifying is highlighted in red, purely for clarity. You can add extra arguments to your signal function on the right hand side, but I'll cover that at a later date.

On the bottom, you can see that the path to the currently selected node is displayed. Since I have highlighted "Node", the path to the selected node is just ".."

The last field, "Method In Node" tells you the name of the function that is going to be created when we connect our signal. I'll leave it as "_on_collectable_body_enter", since this is a fairly self-explanatory function name.

Let's select "player" and press "Connect".

You should see that this opens the script editor with the function already created. Let's do something that makes a fairly visible difference - let's double the player's speed every time they enter the Area2D.

func _on_collectable_body_enter( body ):
    SPEED = SPEED * 2

I should also note that the argument "body" is actually the object that enters the Area2D. In our case, it would be the player node. Now that we've set this much up, we can press play and see how it works.

Hopefully, it does work and we get super fast. However, we can't really make use of this cool new speed with that big wall in the way!

Let's delete the wall when we touch the collectable. Fortunately for us, referring to another object is very easy with our best friend "get_node()". I'll show you an example, then I'll explain how it works.

func _on_collectable_body_enter( body ):
    SPEED = SPEED * 2

You might be able to see that we're referring to our wall(unintuitively named "KinematicBody2D") by using the "get_node" function. The get_node function takes in a node path as a String, and returns an object. If it can't find an object at the end of the path, then it throws an exception and crashes your game, so be careful.

If you're familiar with directory structures, this bit will be super easy for you. However, if you're not, then I'm going to explain it a bit more.

In most operating systems, if you type "cd .." into a terminal it'll move you to the previous directory. For example, if you're currently in the folder "alex/Documents/secrets", typing "cd .." would take you to "alex/Documents". If you then wanted to access the folder "alex/Documents/big_secrets", you would type "cd big_secrets". You would then be taken to "alex/Documents/big_secrets".

However, you can also condense this down to one line. From "alex/Documents/secrets", you can type "cd ../big_secrets" and be taken out one level, then back in one level into the directory of your choosing. The same principle holds for Godot's node paths.

Using the get_node() function, we can call functions like set_pos(), get_pos(), or in our case, queue_free(). queue_free() flags the object for deletion, and frees the memory it's using up. In effect, queue_free() removes the object from the game.

Now that we've done this, we should be able to run our project and see that unsurprisingly, our wall disappears! Hooray! It's kinda like our own scripted cutscene. Kinda.

You might also realize that if you move over the Area2D again, it crashes the game. Remember earlier when I said that if get_node() can't find a node at the specified path that it throws an exception? That's exactly what is happening here. Since we just removed the object, it can't find anything at that path.

The solution here is to globally define a boolean variable(something like var wall_destroyed = false), and only delete the node if wall_destroyed is equal to "false". I won't write out the code here, I'll leave this one as an exercise to the reader.

That's really all there is to cover in this tutorial, so have a play around with it and see what else you can come up with. Thanks for reading, and stay tuned for Part 7, where we'll delve into instancing- for real this time.

Part 5:


  1. Thank you for this tutorial! You are a great teacher. Do you think I could make I game like Pong with your tutorials + the documentation/tutorials of Godot? Or do I need to see more parts of this tutorial?

  2. Hmm, I think you very likely could make Pong at this stage! I think that part 7 (due tomorrow) would also be super helpful, though. Start now, worry later. Good luck!!

    1. Ok, so I'll wait to part 7. How many parts do you think the gitting gud at godot is going to have?

    2. I think it will have around 10-12 parts for now, though I'll be returning after a break with some project-based tutorials.

  3. I don't know if I simply laugh at everything or what, but I enjoy your humour :) Thanks

  4. Since this tut, we have been blessed with a new function to check if a node exists, so we can steer clear of global variables!

    func _on_Powerup_body_entered(body: PhysicsBody2D) -> void:
    SPEED = SPEED * 2
    if is_instance_valid(get_node("../Wall")):

  5. Your tutorials are really good. I feel like I am learning a lot of things while at the same time, I did not feel overwhelmed by the amount of information.

    Thank you for your tutorials