2
\$\begingroup\$

A bit about the physics engine: Bodies are all rectangles. Bodies are sorted at the beginning of every update loop based on the body-in-motion's horizontal and vertical velocity (to avoid sticky walls/floors). Solid bodies are resolved by testing the body-in-motion's new X with the old Y and adjusting if necessary before testing the new X with the new Y, again adjusting if necessary. Works great.

Ramps (rectangles with a flag set indicating bottom-left, bottom-right, etc) are resolved by calculating the ratio of penetration along the x-axis and setting a new Y accordingly (with some checks to make sure the body-in-motion isn't attacking from the tall or flat side, in which case the ramp is treated as a normal rectangle). This also works great.

Side-by-side ramps, eg. \/ and /\, work fine but things get jittery and unpredictable when a top-down ramp is directly above a bottom-up ramp, eg. < or > or when a bottom-up ramp runs right up to the ceiling/top-down ramp runs right down to the floor.

I've been able to lock it down somewhat by detecting whether the body-in-motion hadFloor when also colliding with a top-down ramp or hadCeiling when also colliding with a bottom-up ramp then resolving by calculating the ratio of penetration along the y-axis and setting the new X accordingly (the opposite of the normal behavior). But as soon as the body-in-motion jumps the hasFloor flag becomes false, the first ramp resolution pushes the body into collision with the second ramp and collision resolution becomes jittery again for a few frames.

I'm sure I'm making this more complicated than it needs to be. Can anyone recommend a good resource that outlines the best way to address this problem? (Please don't recommend I use something like Box2d or Chipmunk. Also, "redesign your levels" isn't an answer; the body-in-motion may at times be riding another body-in-motion, eg. a platform, that pushes it into a ramp so I'd like to be able to resolve this properly.)

Thanks!

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

There are two things you generally do in a "real" physics engine to resolve issues like these. It sounds like you're basically writing a simplified separating-axis style of collision response, but then trying to immediately correct position based on each collision. That leads to jitter in exactly the kinds of scenarios you describe.

The first technique you can use is to simply detect all collisions first, then resolve them. That is, instead of detecting that the object has collided with a bottom ramp, fixing the position, then checking for the top ramp, and fixing again, test and see that the object is colliding with both ramps and then calculate a correction that pushes the object out of both items. This can be done generically for ramps, walls, floors, ceilings, and other objects fairly well (but not perfectly in particularly complex scenarios).

The second technique -- which is best combined with the previous technique -- is to run through several iterations of the collision resolution each game update loop. If you think about it, your problem is basically that it takes several frames for your collisions to be fully resolved, because you're only doing one physics pass per frame. If you were to do 10 iterations of the physics handles for each object each frame, your problem would likely disappear (in your current situations at least).

Those are both fundamental requirements for a proper physics engines. Platformers are rarely implemented using proper physics, of course, not least of all because real physics don't make for good platformer behavior (which needs to be closer to Mario physics to "feel" right).

Platformers (and even many modern games) use character controllers that are not modeled after physics at all. It's not at all uncommon to just use a bunch of ray/segment casts before moving the character to see if or what it will collide with, and then moving it appropriately. For a rectangular hit box, for instance, you might do some segment/level collision tests for three or so hotspots per side of the character, and then use the detected limits along with the current velocity to move the character without ever penetrating the level geometry. This technique does not work well with the upside down V shapes though (^, /\, however you want to draw it), so if your level uses those you might also want to combine with a simple resolution system that pushes the character up if it goes through any floors. Walking up ramps is just more special logic detecting that the player is trying to move into an angled surface. Likewise, walking down ramps is a special case that is explicitly checked for, which actually can result in much better behavior that the "physics" way of doing things (where characters tend to walk off, fall down onto, and then jitter down ramps; this is visible even in many AAA games today that are trying to use physics to model character movement). Moving platforms are again just another set of special checks and rules for resolving collisions and pushing. You can mix this character controller with a physics engine to allow players to push physically-modeled boxes and other objects around as well.

\$\endgroup\$
1
  • \$\begingroup\$ As I was writing this question I was starting to think that a second pass on each frame might be all that's necessary to resolve the problem. I'll give it a shot. \$\endgroup\$ Commented Nov 18, 2011 at 22:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .