Trouble with MovePosition and with sliding along walls in top down character (Kinematic)

So my original design kinda works, but has some issues. It goes like this:

  • Use Vector2.MoveTowards to get a steeringVector based on my current velocity and input movement
  • Cast along the steeringVector, looking for obstacles
  • None? MovePosition
  • Otherwise do some geometry to find a deflection vector to slide along the obstacle
  • If the deflection vector is v. smol, just stop (we are too close to a right angle collision to bother moving)

Otherwise:

  • Cast along the deflection vector
  • No obstacles? MovePosition (aka, slide along the wall)
  • Otherwise, don’t move (you’re in a corner of some sort)

So this generally works, with some quirks. Namely, the faster you approach an obstacle, you further away from it you stop (or begin sliding tangentially along it)

So I was considering, instead:

  • Look at the first cast, and move to the hit.centroid
  • Calculate the fraction of the steeringVector we’ve traveled.
  • Calculate the deflection vector and use whatever fraction we have yet to move to slide along the wall.

This seems like it almost would work, but there are some issues:

  • If I move to the hit.centroid, I get stuck in the wall. I instead move to the centroid minus an offset (this kinda makes sense with float math, I’m not suprised I need a buffer)
  • MovePosition doesn’t happen immediately, so the deflection cast doesn’t actually happen from alongside the wall, it happens from the same position as the first cast.

This second issue is the kicker… It can cause wall clipping/getting stuck on weird geometry, especially when moving fast.

Questions:

  • Is there a handy way to perform the second cast from the “wall hugging” position without waiting a frame for MovePosition to actually move the rigidbody there (which seems untenable)?
  • Am I overcomplicating this? Are there better approaches to obstacle sliding a kinematic rigidbody?

Ok, so I tested out adding a “sliding” state. Basically:

if (!sliding)

  • if (first cast hits a wall),
    • movePosition(hit.centroid - buffer)
    • sliding= true.

else // we started this frame sliding

  • If (first cast hits nothing) sliding = false.
  • if (sliding and our first cast hits a wall), deflect and cast/move as in the original appraoch above.

Basically it’s just breaking up the “move to the wall, then start sliding” across frames so that MovePosition has time to do its thing.

This generally seems to work (I’m not stoked about the wall “eating” the rest of the first frame’s movement, but that’s a small gripe), but it seems like i can still get stuck on corners/seams between colliders from time to time.

I cranked up the “collision offset” from 0.01 to 0.05 and that seems to keep me from getting stuck. I’ll call that good enough, but it makes me leery (and it uses up 10% of the width of a unit-wide hallway, which is troublesome)

I’d still love any feedback folks have.