Handle lasting collisions in Godot


If you want to react to the start of a collision there's the body_enter signal. If you want to react to the end of a collision there's the body_exit signal. But what if you need something to happen for as long as the collision lasts? This projects shows how to use get_overlapping_bodies() to solve that problem.

The following article is just a short explanation of the project. For details check out the project files.
Artworks done by Wciow / John.d.h and Alejandro Ballestrino.


Overview

This project contains two solutions, a simple one using coroutines and a more elaborate one using animations. Both solutions have their advantages. Animations may seem more complicated at first, but then the first solution uses signals, coroutines and a timer, all of which are not necessary in the second solution.

The game scenes

In both examples the game scene contains a wall that has a static body as its root node and that has a script attached that allows the wall to receive damage. Once the hitpoints of the wall reach 0 it's removed using queue_free().

Solution 1: using coroutines

Solution 1 also contains an "Enemy" that is walking to the right. This is performed by simply calling translate() from within _process().
Once the enemy's targeting area collides with a wall the body_enter-callback is run and the process-function is deactivated, making the enemy stop. The body_exit-callback reactivates the process-function, so once the wall is down the enemy will continue moving.

The coroutine

The body_enter-signal also called attack(), and that is the coroutine I mentioned before. This function uses get_overlapping_bodies() to get a list of all targets in range. Any of those targets that is able to receive damage is then told to do so.
If there were any targets the cooldown timer is started and the coroutine pauses until the timer sends its timeout-signal. Once that happens the attack()-function simply calls itself to perform the next attack.

Solution 2: using animations

The second example uses animations, since they are basically just a graphical interface to write coroutines.
The spider in this example has three animations: one for walking, one for attacking and one for the idle state that is actually not in use in this demo. The walk animation just updates the frame index. The attack animation on the other hand replaces the coroutine from the first solution.
Besides the track that updates the frame index it also contains a call func track that calls deal_damage().

Checking for collisions

In the _process()-function the spider first checks whether there are targets inside the targeting area. This is necessary because unlike GDscript coroutines animations don't have conditions, so all checks have to be performed outside the animations.
If there is a target attack() is called, otherwise walk() is called. Attack() and walk() check if the animation with the same name is currently running. If it isn't running or if there is a different animation enabled the animation player is told to run the correct animation.

Attacking from within the animation

The benefit of this solution is that now it's fairly easy to set the point in time when the damage is supposed to be dealt. In this case I moved the key on the call func track a little to the right so that the damage is dealt when the animation looks like the spider is hitting its target.
This key calls deal_damage. Inside that function first the list of targets is retrieved from the targeting area using get_overlapping_bodies(). This is necessary because we can't be sure that the target we saw when we started the animation is still present. If it is it's dealt damage.
Note that this second solution doesn't need a timer, because the length of the attack animation serves as a cooldown. Also it doesn't need to react to the body_enter and body_exit signals, because there can only be one animation running at a time in one AnimationPlayer, so we don't need to make sure that the enemy is switching correctly between moving and attacking.