4
\$\begingroup\$

I'm working on a 2D tile-based platformer that supports 45-degree slope tiles.

There are several questions on the topic, but none seem to cover this precise problem that I have. This excellent article covers almost everything I'd want to know. I'll copy the salient bits:

  • Make sure that you step X position before Y position.
  • During collision detection, the slope only counts as a collision if its closest edge is the taller (smaller y coordinate) one. This will prevent characters from “popping” through the slope from the opposite side. [...]
  • A full obstacle tile adjacent to the slope the character is currently on should not be considered for collision if it connects to the slope, that is, if the character (that is, his bottom-center pixel) is on a {0, *} slope, ignore left tile, and, if on a {*, 0} slope, ignore the right tile. You may have to do this for more tiles if your character is wider than two tiles – you might simply skip checking on the entire row if the player is moving towards the upper side of slope. The reason for this is to prevent the character from getting stuck at those tiles (highlighted yellow above) while still climbing the slope, as his foot will still be below the “surface level” by the time he comes into contact with the otherwise solid tile.

So if the character is going uphill, we essentially allow him to penetrate the slope after we've stepped the x coordinate, and then rectify that when we step the y coordinate. Let's assume we're using one contact point for the characters feet:

Normal case

However, when the character reaches the top of the slope, at some point he'll step into the next tile:

Problem case

As per the last bullet point above, we allowed him to move into the solid tile because it's ajacent to the slope. But now we're inside the floor, which needs to be fixed somehow.

What logic is needed to correctly resolve this situation? Simply saying "if we penetrate a solid tile, move up until we're out of it" doesn't always work, because there might be another solid tile on top of it, and we don't want the player to be teleported all the way to the top.

Can this be done without any communication between the x update and the y update, or do we need to keep some state like "I was on a slope at the start of this frame"? What is the most robust and elegant way to handle this?

\$\endgroup\$
4
\$\begingroup\$

The answer is to not use just SAT and plain physics/collision handling but to add a large mass of character-specific collision-handling code. Platformers are special beasts with special rules.

As the player moves, remember that he is on the ground. Adjust along the slope horizontally then snap the player back onto the ground afterward. Otherwise you end up with the player "hopping" off the top of slopes or what running down a slope, as you noted.

You may well want all kinds of special logic for slopes to deal with speed (if you only have horizontal speed, the player will move faster/farther on a slope than not), jumping (with plain SAT or such, the player will "bounce down" a slope slightly every time they land on one from a jump, since they will be pushed out along the normal of the slope rather than having their vertical jump simply stopping).

Instead of physically modeling the movement, just have multiple states: grounded and in-air. If ground, any movement should keep the player snapped to the ground unless he is walking off a vertical drop, in which case you switch to the in-air state. Go back to grounded once landing. While in air, remember to first check for separating axis along the bottom of the player to avoid the "hopping" problem on slopes.

You can use hotspots or multiple ray casts to detect if the player is half-standing on a ledge or slop for animation purposes.

Overall, player controllers and physics are very rarely tied tightly together, and platforms even more so. Your player will typically be an infinite mass kinematic object in most cases (with maybe a special "ragdoll" like mode if thrown or struck) that is explicitly managed with custom set of algorithms, using the collision system for queries and basic resolution but not full physical resolution.

\$\endgroup\$
  • \$\begingroup\$ I'm not using a general-purpose physics engine (e.g. Box2D). I know it's a bad idea to do so. Did you have a look at the article I linked to? It describes how to solve all these problems, using many examples from classic platformers -- except that it's unclear about the problem I described in my question. \$\endgroup\$ – Thomas Sep 17 '13 at 10:38
  • \$\begingroup\$ Snapping to the floor fixes the problem. He was on the ground. Now snap his position to the ground for his new tile. If the tile he is in is solid, it's ground plane is what he's snapped to. If the tile is empty, try to snap him to the solid one below him. If there is no such, or the distance is larger than some heuristic (say, 1/10th a tile height), he must've walked off a ledge. \$\endgroup\$ – Sean Middleditch Sep 17 '13 at 16:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.