godotengine / godotengine/godot
CharacterBody3D with skeleton and root motion animations gets stuck against other physics objects
- Dominant language
- C++
- Stars
- 117k
- Forks
- 26.8k
- PR merge metrics
- PR metrics pending
Description
### 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)
[stuck.zip](https://github.com/godotengine/godot/files/14910288/stuck.zip)
https://github.com/godotengine/godot/assets/91064515/b66fef75-3144-4d61-822f-4b89d1a1cc9c
Contributor guide
Research direction
Start with CharacterBody3D::_move_and_slide_grounded() and the three velocity assignments highlighted in the issue. Run the stuck.zip reproduction and walk the character against the cylinder wall. Done means root-motion CharacterBody3D instances no longer get stuck against physics objects while retaining appropriate slope and sliding behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- game-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100