godot
godot copied to clipboard
CharacterBody3D with skeleton and root motion animations gets stuck against other physics objects
Tested versions
- Reproducible in v4.3.dev.custom_build [0c6b5efab]
System information
Godot v4.3.dev (0c6b5efab) - Windows 10.0.22631 - Vulkan (Forward+)
Issue description
When running against another physics object with CharacterBody3D with a skeleton and root motion animations the body gets stuck against other physics objects. Using a capsule as the main physics collider.
Looking into this a bit more it seems there are three places in move_and_slide() that can cause the horizontal velocities set to zero.
@@ -178,11 +178,11 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
if (motion_vertical_velocity.dot(up_direction) > 0 || ceiling_vertical_velocity.length_squared() > motion_vertical_velocity.length_squared()) {
velocity = ceiling_vertical_velocity + velocity.slide(up_direction);
}
}
}
-
+ // HERE (the velocity vector is cleared a bit lower, but the < 0.01 seems a bit arbitrary)
if (collision_state.floor && floor_stop_on_slope && (velocity.normalized() + up_direction).length() < 0.01) {
Transform3D gt = get_global_transform();
if (result.travel.length() <= margin + CMP_EPSILON) {
gt.origin -= result.travel;
}
@@ -250,10 +250,11 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
if (vel_dir_facing_up) {
Vector3 slide_motion = velocity.slide(result.collisions[0].normal);
// Keeps the vertical motion from velocity and add the horizontal motion of the projection.
velocity = up_direction * up_direction.dot(velocity) + slide_motion.slide(up_direction);
} else {
+ // HERE (this cancels out the movement sometimes, perhaps a rotation issue)
velocity = velocity.slide(forward);
}
// Allow only lateral motion along previous floor when already on floor.
// Fixes slowing down when moving in diagonal against an inclined wall.
@@ -291,10 +292,11 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
if (p_was_on_floor && (wall_min_slide_angle > 0.0) && result_state.wall) {
Vector3 horizontal_normal = wall_normal.slide(up_direction).normalized();
real_t motion_angle = Math::abs(Math::acos(-horizontal_normal.dot(motion_slide_up.normalized())));
if (motion_angle < wall_min_slide_angle) {
motion = up_direction * motion.dot(up_direction);
+ // HERE (this cancels the movement sometimes, perhaps a rotation issue)
velocity = up_direction * velocity.dot(up_direction);
apply_default_sliding = false;
}
}
Removing these velocity assignments on those lines will fix the getting stuck. But the character will slip and slide.
Steps to reproduce
Run the test project and walk against the cylinder wall for some time.
Minimal reproduction project (MRP)
https://github.com/godotengine/godot/assets/91064515/b66fef75-3144-4d61-822f-4b89d1a1cc9c
@TokageItLab Is this related to the root motion in animations problem?
@fire No, it is not relevant animation as the root motion is just a value. I do not know how the authors of the issue apply the root motion, but this is a physical area issue as long as it is applied as follows as I have wrote in the document:
func _process(delta):
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
var velocity: Vector3 = (animation_tree.get_root_motion_rotation_accumulator().inverse() * get_quaternion()) * animation_tree.get_root_motion_position() / delta
set_velocity(velocity)
move_and_slide()
If the root motion is being added directly to the coordinate values, then the script is wrong.