Let's say there is a (simplified) scene, where there is a StaticBody2D (the ground), above it there is a CharacterBody2D, and above that, there is a RigidBody2D. Each one of them has a CollisionShape2D with a RectangleShape2D.
The setup with visible CollisionShape2Ds
The CharacterBody2D has a script attached to it, the "CharacterBody2D: Basic Movement" template:
extends CharacterBody2D
const SPEED = 300.0
const JUMP_VELOCITY = -400.0
# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
func _physics_process(delta):
# Add the gravity.
if not is_on_floor():
velocity.y += gravity * delta
# Handle Jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get the input direction and handle the movement/deceleration.
# As good practice, you should replace UI actions with custom gameplay actions.
var direction = Input.get_axis("ui_left", "ui_right")
if direction:
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
move_and_slide()
Every other setting is at the default.
When I hit the play button, the CharacterBody2D and the RigidBody2D start falling, as expected. When the CharacterBody2D hits the ground, it stops, however, when the RigidBody2D hits the CharacterBody2D, it pushes it into the StaticBody2D ground for a moment.
CharacterBody2D is in the ground
Red markers appear a bit later
I'm using Godot 4.1.
I've tried to replace the CharacterBody2D with an other RigidBody2D, and this works as expected: no object is inside the ground on impact. However, I need to control a character in my original game, so this is not a good solution.
I've also tried to comment out the
# Add the gravity.
if not is_on_floor():
velocity.y += gravity * delta
part. It only makes a difference if I put the character in the air. If the character is already on the ground, it's the same. (And of course, I'd lose gravity on the character.)
I've came up with a hacky solution which I don't like. By replacing the move_and_slide() call with this:
var pos = position
move_and_slide()
if is_on_floor():
position.y = pos.y
the problem disappears. However, I think this is a hack, and I miss some settings instead. Or maybe this is a bug in the engine?
Is there a better way to prevent this glitch to happen?