Skip to content

Implement move-and-slide#894

Merged
Jondolf merged 124 commits into
avianphysics:mainfrom
janhohenheim:cns
Nov 25, 2025
Merged

Implement move-and-slide#894
Jondolf merged 124 commits into
avianphysics:mainfrom
janhohenheim:cns

Conversation

@janhohenheim

@janhohenheim janhohenheim commented Nov 17, 2025

Copy link
Copy Markdown
Member

Objective

Solution

  • Provide a MoveAndSlide SystemParam with an eponymous move_and_slide function
    • Implemented as a pure function, i.e. it does not mutate the ECS by itself
    • Returns a new position and velocity after movement and sliding along surfaces is complete
    • Every collision encountered during the slide is fed to a callback for optional processing. The callback is allowed to early-abort the slide.
    • Note: Currently, move_and_slide should be used to modify Transform, not LinearVelocity. The returned velocity should be stored elsewhere and passed to the next move and slide call to preserve momentum. ECS integration with LinearVelocity will be added later.
  • High level overview: (edited by @Jondolf to match new multi-plane solver)
    1. Initial Gauss-Seidel depenetration pass
    2. For each iteration, until movement is done or max iterations reached:
      • Sweep the shape along the velocity vector
      • If we hit something, move up to the hit point
      • Collect contact planes
      • Project velocity to slide along contact planes
    3. Final Gauss-Seidel depenetration pass
  • Inspirations
  • Prior work in Avian KCC tech and comparison
    • kcc_prototypes:
      • very similar API
      • switched to Q3 plane solver, but then a hard-drive failure erased the progress.
      • no depenetration
    • avian_collide_and_slide:
      • uses Q1 plane solving
      • no depenetration
    • bevy_fps_controller:
      • Q1/Source inspired
      • no exposed collide-and-slide
      • no plane solving
      • no depenetration
  • Special thanks to @UndefinedBHVR, who spearheaded a first iteration of collide-and-slide that I was able to iterate on and who's breadcrumbs I followed a lot ❤️
  • TODO:

Out of Scope for this PR

  • Example KCC implementation
  • Changing the existing KCC examples
    • I think these should just be entirely rewritten later on
  • predicting intersections with moving bodies
  • calculating forces to be exerted onto touching dynamic bodies and vice versa
  • minimal examples, for now we just have the in-depth testbeds
  • a more diverse 2D testbed: requires parsing SVGs like Box2D

Testing


Showcase

2025-11-22.15-27-54.trimmed.mp4

@janhohenheim janhohenheim added D-Modest A moderate level of difficulty: suitable for simple features or challenging fixes A-Character-Controller Relates to character controllers S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged C-Examples Improvements or additions to examples A-Collision Relates to the broad phase, narrow phase, colliders, or other collision functionality labels Nov 20, 2025
@janhohenheim janhohenheim added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention to move forward labels Nov 25, 2025
@Jondolf Jondolf merged commit ca51627 into avianphysics:main Nov 25, 2025
6 checks passed
Jondolf added a commit that referenced this pull request Mar 4, 2026
# Objective

Fixes #273

#894 implemented the move-and-slide algorithm for building kinematic
character controllers. However, our KCC examples don't actually use it
yet! To demonstrate how it can be used, and have better KCC examples for
Avian, we should update the examples.

## Solution

Use `MoveAndSlide` for the `kinematic_character_2d` and
`kinematic_character_3d` examples. This involved some tricky bits:

- Slope climbing and sliding is handled in the `on_hit` callback. This
is the most complicated part. I partially adapted the logic from Rapier.
- The callback also tracks collisions. Contact forces are applied to
dynamic bodies in a separate system.
- I really struggled to get characters not to slide down walkable slopes
when standing still. This turned out to largely be a bug in `cast_move`;
the skin width wasn't considered in the shape cast `max_distance`,
causing the character to move past the skin width, at which point
depenetration kicked in, moving the character along the normal, causing
drift down the slope. This is now fixed.

I also improved the examples in general:

- Added `TransformInterpolation`
- Changed scheduling to collect inputs in `PreUpdate` and handle
movement in `FixedUpdate`
- Added terminal velocity
- Made the component split a lot more sensible and got rid of bundles
- Made damping use exponential decay like `LinearDamping` does

## Testing

Ran the examples a bunch of times.

---

## Showcase

`kinematic_character_3d`


https://github.com/user-attachments/assets/1b41c568-2046-4b70-b79f-bf4f22d51379

Previously, the box would fly away as soon as you stand on it or push it
into a wall. With move-and-slide and manually applied impulses, this
doesn't happen.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Character-Controller Relates to character controllers A-Collision Relates to the broad phase, narrow phase, colliders, or other collision functionality C-Examples Improvements or additions to examples C-Feature A new feature, making something new possible D-Modest A moderate level of difficulty: suitable for simple features or challenging fixes S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Contentious There are nontrivial implications that should be thought through

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement collide_and_slide

3 participants