42
\$\begingroup\$

I am looking for a conceptual solution to my problem. It's a simple platformer-alike game where player can move horizontally during free-fall.

Consider those two cases:

In the first case, from game experience point of view, the player should land on top of the box; and in the other case he hit the left edge, hence the player should fall down.

However, from my code point of view ("real behaviour"), both those collision detection cases are identical. I am not sure how to separate them.

In both cases the vertical velocity is positive (falling down) and the user is moving with some fixed positive horizontal velocity. (moving right)

From a collision-standpoint the two cases are identical, I think. How can I tell whether I should put the player on top of it or let him fall?

\$\endgroup\$
2
  • 17
    \$\begingroup\$ It sounds like you're detecting collisions by checking for intersections at discrete times (i.e., once per frame). This is a fine naïve approach, but suffers from lots of problems, including tunnelling. Consider looking into other approaches, like swept collision detection, that properly simulate time-continuous processes rather than just their discretizations! \$\endgroup\$
    – wchargin
    Nov 25, 2019 at 0:45
  • 5
    \$\begingroup\$ A simple way would be to compare the aspect ratio of the velocity vector and the collision overlap. If the aspect ratio of the overlap is higher, you reached the top; otherwise, you hit from the side. Note that this is not perfectly precise (it essentially assumes the velocity didn't change during the interpolation between two frames, which isn't true), but it's simple and usually looks fair :) Alternatively, you can just rewind the physics simulation to find the exact point of contact, which gives you a precise answer. \$\endgroup\$
    – Luaan
    Nov 25, 2019 at 9:46

1 Answer 1

48
\$\begingroup\$

There are three common ways games sort this out:

  1. Minimum Separation Vector

    Upon a collision, compute the shortest movement that pushes the bodies apart into a non-intersecting position.

    If I've crept just 0.1 units into the platform's left side, but my feet are 0.2 units below its top surface, then the shortest movement to resolve the penetration is to shift me 0.1 units directly left.

    If the penetration from each face is the same, you can pick one arbitrarily.

  2. Rewind to Moment of First Intersection

    Knowing the penetration depth of the object and its incident velocity, you can compute the moment in its travel this frame that it first contacted the obstacle, and back-track it along its velocity to the moment of contact. This will generally be a diagonal movement, rather than favouring the horizontal or vertical axis exclusively.

    That rewound position will sit either wholly to the left, or wholly above, or exactly corner-to-corner in the most extreme case.

  3. "Love the Player"

    For the particular case of the player controller, we might want to use player experience rather than geometry to guide us.

    As you say, these two situations look almost identical to the player - if in one case they fall and one they land, based on tiny fractional differences in the numbers, then the mechanic is liable to appear inconsistent, capricious, and frustrating to the player.

    Instead, we can choose to make a charitable assumption that honours what the player was trying to do: as long as they haven't sunk too far below the top of the platform (maybe use their falling speed times half a frame as a threshold), correct them to the top of the platform as though they landed on it, even if a perfectly continuous simulation would have said otherwise.

    This will only fudge the player's position by a half a frame's movement, tops, so it generally won't be very noticeable if you choose a suitable threshold, and a landing sprite/animation/dust cloud/sound effect can help sell the landing and mask the fudge factor.

    If you want to increase this tolerance range further, you can add a ledge grab state to trigger on near-misses like this and save the player from a fall when they were "close enough" for your game's target experience, even if raw physics disagrees.

\$\endgroup\$
6
  • 9
    \$\begingroup\$ @CalebMiller "as long as they haven't sunk too far below the top" effectively reduces the height of the hitbox by a certain amount ("maybe use their falling speed times half a frame"). This new, reduced hitbox still has a corner one can hit, repeating the problem. It should maybe be listed as an additional hint, not as a solution to the problem. \$\endgroup\$
    – WhiteMaple
    Nov 25, 2019 at 9:29
  • 5
    \$\begingroup\$ @WhiteMaple it doesn't reduce the height of the hitbox, it just introduces a simple threshold value exclusive for the Y axis. No matter how far the X-Position overlaps, if Y is smaller than the threshold the player gets teleported on top, otherwise he will always get moved to the side. \$\endgroup\$
    – Falco
    Nov 25, 2019 at 12:12
  • 19
    \$\begingroup\$ WhiteMaple is right that there is still a point where a player at x,y falls, and a player at point x,y+0.0001 lands. There will always be such a cut-off point (unless you add a ledge grab state between the two extremes). What approach #3 does is move that transition point away from the place where, visually, it looks plausible that I should have landed, where a player might be very legitimately frustrated that they fell instead. This way, the player who is closest to landing but still falls is visibly not close to the rendered corner, so it's more obvious that "oops, that was my fault" ;) \$\endgroup\$
    – DMGregory
    Nov 25, 2019 at 13:20
  • 2
    \$\begingroup\$ I realize there is a new cutoff point different than what is shown visually, but I don't understand how the problem becomes recursive. How does a single small threshold check (and possible correction on Y axis) lead to a repeating problem? If we're talking about the possibility of extreme overhang (like the player only sitting on a single pixel of the box) the ledge grab state is another great solution offered. Unless dealing with a strict physics sim (option 2 shines there), I think all of the details given in option 3, along with the general idea of "love the player", is great advice. \$\endgroup\$ Nov 25, 2019 at 16:11
  • \$\begingroup\$ @WhiteMaple For option 3, a good solution would be to have the animation and player model be obvious on how you can land on a ledge like that. If the model is a humanoid, you can have a somewhat intuitive center of mass and have a special ledge grab animation if the player lands with his center of mass above the ridge. That way, it's also a bit more intuitive where the cutoff point for "Am I grabbing the ledge?" is, and you can then also inform the player of this point by adding something like a satchel on that spot. \$\endgroup\$
    – Nzall
    Nov 26, 2019 at 9:50

You must log in to answer this question.

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