Getting inaccurate results when polling Area2D with get_overlapping_bodies()

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By RWmkII
:warning: Old Version Published before Godot 3 was released.

To give some context, I’m trying to implement a Castlevania-like knockback when my character takes a hit.

The damage function puts the character in a stunned animation and gives them an up-back velocity to knock them in the air. They’re supposed to stay in this state until touching the ground again.

I got the desired behavior when I took a hit in the air, but when taking a hit on the ground the character would immediately return to the neutral state without even leaving the ground. Now one of the things I do every frame is reset the character velocity if they’re standing on firm ground, and the way I check for firm ground is checking if there’s anything inside a little Area2D I have under the character’s feet using get_overlapping_bodies(). The only layer in this area’s mask is a layer where I only put terrain bodies, so anything this area2d finds can be stood upon.

I concluded that I was giving the character an upwards velocity, but before it could move, the script detected the ground and reset it along with the stun animation. So I added an extra push upwards to the damage function, to take the character off the ground before the area2d got polled in the next frame.

Somehow it still finds the ground in the next frame. I added a set_pause(true) to the code so I could capture the moment right after get_overlapping_bodies() returned something but you can clearly see there’s nothing under the character. The “extra push” I mentioned earlier was also exaggerated (100 pixels) to avoid all doubt. See picture below.

I put cuts of the code in it too, rather than pasting here on the post, because I wanted to draw those arrows and show where everything is, because I’m suspecting the order things get resolved is responsible for this behavior.

Now this is where I start to speculate and I’d appreciate if someone more knowledgeable could clarify. I think when you call get_overlapping_bodies() the area2d is not polled at that exact instant, it returns the results from the last time the node was “resolved”, which happens every frame in the order nodes are arranged in the scene tree. So since the player script that calls the check_ground() function is higher than the Feeler_Ground area2d in the tree, it actually gets results from the last frame, because the area hasn’t updated yet.

I thought this couldn’t be the problem because the hurtbox script where the damage function resides is in a node between those two, so any changes made by it would be reflected in the Feeler_Ground update before check_ground() was called again. It occured to me right now while writing this post that the damage function is actually called by the bullets that hit the player and are in another position entirely in the scene tree, so the change in the player position could certainly be happening between the area2d update and get_overlapping_bodies() call.

So with that last insight I guess what I want to know is if that’s really the way Area2D works. In that case I might have to put that particular check in a separate _on_body_enter() function, or maybe trade the whole thing for raycasts instead.

Anyway thanks for reading, sorry for the ultra long post but I thought I had to tell the whole story.

:bust_in_silhouette: Reply From: puppetmaster-

Look at the GBot tutorial Serie (https://www.youtube.com/watch?v=Qe7NxP6cyJk).

It uses RayCast to check if it stands on the floor.
Watch out, RayCast can only report one touch. Be aware when you create Ray in editor it touches only things you have added as exception (player body).

My pitfall are always raycast touch other raycast.