0 votes

I have a KinematicBody2D player object and some StaticBody2D platform objects. If the player collides with an object with a normal within an angular range that I've designated as the floor, I want the player to adjust its rotation to match the angle of the floor and snap down (i.e. rotate about the corner that contacts the surface). This is fine until we encounter a situation in which the player contacts the sloped floor at a position where the floor intersects another platform that's at a different angle, since rotating and snapping down would cause us to intersect and jitter between the two floors.

My proposed solution was to rotate and snap, and then check if we're intersecting any platforms. If we aren't intersecting, we're fine and can move on, but if we are intersecting, then undo the rotation and snap, and try again with a smaller angle a few times to find a close approximation to the angle that rests the KinematicBody2D's CollisionShape2D on top of both platforms, at the angle of the line between the collision points (see image below).
KinematicBody2D resting between StaticBody2Ds

My problem lies in the ability to check if our rotation would cause an overlap. If using test_move with a rel_vec argument of Vector2(0,0), we still detect a collision even when just sitting on a single floor, I guess since the objects are touching (I measured to ensure my math was correct, and the player rests perfectly on the floor).

My next thought was to try attaching an Area2D to the kinematic body with the same CollisionShape2D as the one I attached to the kinematic body, and then call get_overlapping_bodies on it, but if I'm interpreting the results correctly, it doesn't count the new overlapping platforms until the next physics process. I also can't just use an Area2D's overlapping signals, since I need to be able to reverse the rotate and snap mid-process to try a different one.

Does anyone have advice on how to best proceed? Thanks!

in Engine by (84 points)
edited by

1 Answer

0 votes

I ended up solving this using a space state check. This is probably horribly inefficient, but didn't give me any lag at my current project scale. If I run into issues later and manage to find a better solution, I'll return to this post. Using the same methodology I described in the question, I would rotate about the corner we land on, and check my collision using the following code:

space_state = get_world_2d().direct_space_state
params = Physics2DShapeQueryParameters.new()
params.set_shape(hitbox.shape)
params.collision_layer = 2
params.transform = hitbox.global_transform
params.collide_with_bodies = true
collision_result = space_state.intersect_shape(params)

# If this rotation would put us in collision, undo and step
if collision_result.size() > 0:

If the check at the end succeeds, we undo the rotation, and try a rotation at a smaller angle for a few iterations, until we exceed max iterations (I'm using six), only undoing a rotation if we have a collision (so if we don't collide, keep that rotation and then add onto it).

by (84 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.