20
\$\begingroup\$

I'm checking collision for a platformer character as shown in #1. The red dots are the pixels that are checked and the grey lines indicate the axes they pertain to. I like the results I get from checking collision this way (versus, say, bounding box). Everything works exactly as I'd like it except for one problem: crush detection.

In the following images, the light blue box represents the ground, the orange box is an object, and the arrows indicate direction of movement.

The simple solution to detecting when the player is crushed is to see if the collision points on opposite sides are both triggering. If they are, the player is being crushed. In #2, you can see a normal crush scenario. The player is grounded and the top collision points are intersecting with the falling object. This triggers a crush.

#3, 4, and 5 present problematic scenarios. In #3, the player is moving toward the object, which is moving up. A right-side collision point is hitting the object, causing a collision and stopping the player.

Now, if the object continues to move up and the player continues to move right (as shown in #4), the object clears the players right-side collision point and the player moves to the right. But now, having done so, the object is intersecting a top collision point causing an unwanted vertical crush.

A similar scenario is shown in #5. Two objects are far enough apart for the bottom collision points to clear, allowing the player to fall, but no to so far as to allow the side collision points to clear, causing an unwanted horizontal crush.

I've been racking my brain on a solution, but nothing I've come up with has worked particularly well, so I'm wondering if anyone out there has an idea or insight into how to solve these problems.

enter image description here

To clear up some confusion, the red collision points would be within the sprite and the grey lines were only used to denote the relevant axis for each collision point. For example, if the character's sprite was a simple green square, the collion points would look something like this:

enter image description here

\$\endgroup\$

7 Answers 7

34
\$\begingroup\$

I think you'll have to take the box's movement into consideration. That is, only crush if the box is moving towards the player.

This is similar to other problems in platformers, where the movement is important. E.g. for platforms that you can jump through and onto from below, don't check collision if the player is moving upwards.

So a block can crush the player from above only if the block is moving downwards; from below only if the block is moving upwards; from the left only if the block is moving to the right, and so on.

\$\endgroup\$
4
  • 13
    \$\begingroup\$ +1 Take into consideration that the block is acting here, not the player. So if you check if the box is crushing the player instead of checking if the player is being crushed the problem should be easier to solve \$\endgroup\$
    – Niels
    Commented Sep 28, 2017 at 9:55
  • \$\begingroup\$ What about when the blocks aren't moving? I realize now I put arrows on the blocks in #5, but that was meant to be two stationary blocks. \$\endgroup\$
    – IanLarson
    Commented Sep 28, 2017 at 23:40
  • \$\begingroup\$ If you decide that stationary blocks should not crush, just ensure that the player is not stuck and can move out of the way. \$\endgroup\$ Commented Sep 29, 2017 at 0:30
  • \$\begingroup\$ Argh, I hate getting crushed by two objects that are actually moving away from each other, only because I made it there pixel- and frame-perfect and the developer was lazy. \$\endgroup\$
    – rhino
    Commented Sep 30, 2017 at 12:58
9
\$\begingroup\$

Have the "crush test" points be inside the gray box shown in your image #1 - i.e. kill the player only if you detect a hit on one of the pixels there.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Do you mean addition crush check points "inside" the bounds of the collision points? The problem I see with that is that collision resolution will happen in each axis when one of it's collision points is "triggered" before the object even has a chance to reach the inside crush check points. \$\endgroup\$
    – IanLarson
    Commented Sep 28, 2017 at 23:53
6
\$\begingroup\$

As someone who grew up with 80s platformers, my first comment is that the contact points must be exactly on the sprite, not anywhere outside it. There were few experiences more frustrating than dying when a weapon/crusher/enemy was clearly several pixels away from your character - and that kind of experience is what stops people playing.

With that in mind, the idea of having separate points for horizontal and vertical collision simply doesn't fly. So your cases 3 and 5 don't exist.

As for collision detection, as has previously been said, you need to consider movement direction, and you have two axes of movement to consider. If a crusher is down, the player should not be able to walk forwards - it should act like a wall. So with horizontal and vertical detection points in the same place, you couldn't get case 4, even before you add movement direction to the mix.

The upward-moving crusher adds extra complexity. If it's so quick that the player has no chance to escape, then OK. But if it's slower, the player will expect to be able to run over the rising platform and jump off the other side. The player sprite rises upwards on the crusher, and crush detection happens at the ceiling.

\$\endgroup\$
2
  • 3
    \$\begingroup\$ Minor point - you don't know what his sprite looks like. For all we know it could be exactly as shown in the images above, so cases 3 and 5 may be entirely valid. \$\endgroup\$
    – Alex
    Commented Sep 28, 2017 at 13:27
  • 1
    \$\begingroup\$ Alex is right. I made an edit to clarify. I agree that there's nothing worse than inconstant collision boxes. I think I understand your point about not using separate points for the different axes. If I do, that would turn the above example from having eight points to four, one in each corner, correct? I've actually done some testing with that in mind (with less than desirable results), but I'm strongly hesitant to doing that, since having the corners "separated" achieves the behavior I'm looking for nearly perfectly. These are really the only problem scenarios I've run into. \$\endgroup\$
    – IanLarson
    Commented Sep 28, 2017 at 23:50
0
\$\begingroup\$

You could make the object "harder" than the ground, meaning that, assuming collision, the player gets pushed "into" the ground, as opposed to being pushed "into" the moving object.

This assumes the player is not able to push themselves "into" either objects or ground.

\$\endgroup\$
0
\$\begingroup\$

If you can detect overlap of objects without having to wait for them to display, a simple approach is to process motion for the player and other objects independently, one pixel at a time, with separate collision checks afterward. If the player is moving freely and would collide with its object as a result of such motion, back it off. If a collision occurs with an object as a result of the object's motion, check whether the player can move in the same direction as that object. If so, move the player. If not, handle the "crush" situation appropriately (damaging or killing the player and/or moving the colliding object backward, depending upon the contact).

BTW, if only a limited number of combinations of shapes can collide, it may be useful to pre-calculate "collision-detection" bitmaps such that if a pixel is set in the first sprite at offset (x1,y1) and in the second at offset (x2,y2) of the second, the pixel at offset (x1-x2,y1-y2) will be set in the collision map. Such a pre-calculated collision map will make it possible to detect collisions between the two sprites by checking the state of a single pixel in the collision map.

\$\endgroup\$
0
\$\begingroup\$

It takes two objects to crush a player. Your crush detection should check for the player being between two objects, the space between them being equal to the size of the player, and the distance decreasing.

\$\endgroup\$
0
\$\begingroup\$

I find next to be working so far. It doesn't require "external" info about the crushers movement and solves the false positives problem. When a false positive is detected it is treated as collision (and this is what it actually is):

The idea is: why to check if the crusher is moving when we actually care if the character is moving. Both can answer if the crush is false positive caused by the character's own movement or true crush by the crusher object movement.

If the character is moving and crushed (collisions on opposing sides for the incoming frame) then check again for crush on the last frame/iteration coordinates:

  1. If not confirmed again then it is due to character's own movement and the character should be returned to the last frame/iteration coordinates just like a collision

  2. If crush is confirmed the second time then proceed with crush.

\$\endgroup\$

You must log in to answer this question.

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