How to avoid deflection caused by non-perpendicular collisions?

I am working on my first 2D platformer character controller. I have managed to solve the movement on slopes and curved surfaces, but when I started testing collisions on the slopes, some tricky problems began to arise.

Problem 1:

When the character moves upwards on a slope and encounters a vertical wall ahead, the physics system resolves the collision, but the character moves upwards along the vertical wall. This causes my character to hang in the air and enter a falling state. If the player continuously commands the character to collide with the wall, this process repeats, leading to the character shaking.

Problem 2:

When the character jumps and collides with a slanted ceiling, the physics system resolves the collision, but the character moves horizontally along the ceiling for a short distance. This makes the jump feel off, as the character moves horizontally after the collision, even though the player didn’t press any horizontal movement keys. As a result, the character feels somewhat ‘out of control.’ I tested Ori2, and when Ori jumps and collides with a slanted ceiling, Ori will fall straight down. Only when the player presses the horizontal movement key while jumping will Ori slide along the slanted ceiling for a short distance during the collision.

My character uses a Capsule Collider and a dynamic Rigidbody with Continuous collision detection. Moving by assigning velocity in FixedUpdate.

I want to know how to solve the two problems mentioned above. If possible, I would prefer not to change the Rigidbody type and rebuild the character controller from scratch. However, if starting over is a better approach, I am open to trying that.

Quite simply, if you want custom behaviour upon a collision but want to keep a Dynamic body (not sure why right now) then you’ll need to preempt it by performing a query before you move and create the contact(s) in question. If you find that you’ll move into a wall then you can move to the wall and do whatever you want with the velocity.

The fact that you’re moving by directly setting velocity is strange because the solve is trying to also do that so you’re stomping over it. This is typically why you’d use a Kinematic body so you have full control and perform queries to detect your environment.

That said, this is also why there’s a Slide method with a myriad of options that work with all body types, including Static and can also move immediately or during the simulation step.

In short though, no, there isn’t a way to change the behaviour of the solver contact resolution beyond the friction/bounce arguments.

@MelvMay Thank you for your reply! Your answer has pointed me in the right direction to explore further.

After posting, I went through many discussion threads about Kinematic and Dynamic Rigidbody. I even studied the documentation and source code of the Kinematic Character Controller (a well-known plugin!).

Using a CapsuleCast to probe the movement path, handling collisions along the path with custom code, and then executing the movement—I believe this approach is indeed necessary.

And, I want to explan why I keeped on using a dynamic Rigidbody in my first post, here is my perspective: Starting with a dynamic character controller only requires progressively replacing certain parts with custom code as the situation becomes more complex. However, starting with a kinematic character controller requires building everything from scratch, considering and resolving every possible movement and collision scenario. Just like the difference between doing exclusion and doing addition.

So, what I want to try next is:

  1. Using dynamic rigidbody;
  2. Setting velocity in each FixedUpdate to control the character’s movement;
  3. Actively performing physical queries in each FixedUpdate, and manually resolving certain movements/collisions before physical updates.

But there is still one thing that worries me. You mentioned that “The fact that you’re moving by directly setting velocity is strange because the solve is trying to also do that so you’re stomping over it.”. I would like to know if doing so will cause any bugs or certain weird behaviors? Because so far I haven’t encountered any problems, so I would like to know what specifically will happen if I do so?

Well step back and consider what happens when the physics simulation runs. It’s not as simple as it taking the body velocity, integrating it by the time being stepped and updating the position. You wouldn’t need a physics system for that.

What it does is updates/creates contacts then solves those contacts by applying impulses to the velocity. The velocity is integrated over time to change the position. The same goes for things like joints which apply impulses to the velocity. Also any user-forces and gravity are added to it.

Because you’re overwriting the velocity, you are countering what the solver is trying to do beyond the current step i.e. for the next step and the one beyond that etc.

If you’re using the Dynamic body then the only reason that would be over using a Kinematic body is that you’re using it for collision response. It’s the only difference between the two body types.

Whether you encounter problems or not depends on what you’re doing and how you’re using it, what your expectations are (etc) but it’s important to know how you’re opposing what it’s doing. It’s mostly about understanding what makes a Dynamic body “dynamic” as opposed to a Kinematic or even Static.

We currently use Box2D v2 and you can find a lot more information about how it all works here if you ever need to: Box2D: Overview