I have a problem with AABB collision resolution.















  • 5
    \$\begingroup\$ There actually is nothing going wrong. The method I'm using pushes on the X axis first, then on the Y axis. That's why the player gets pushed horizontally even on the vertical spikes. I need to find a solution that avoids the "jumping problem" and pushes the player on the shallow axis (the axis with least penetration), but I can't find any. \$\endgroup\$ – Vittorio Romeo Jul 4 '11 at 22:09
  • 1
    \$\begingroup\$ You could detect which face of the obstruction the player is touching, and resolve that one \$\endgroup\$ – Ioachim Jul 4 '11 at 23:41
  • 4
    \$\begingroup\$ @Johnathan Hobbs, read the question. Vee knows exactly what his code is doing, but doesn't know how to solve a certain problem. Stepping through the code will not help him in this situation. \$\endgroup\$ – AttackingHobo Jul 5 '11 at 2:12
  • 4
    \$\begingroup\$ @Maik @Jonathan: Nothing is "going wrong" with the program - he understands exactly where and why his algorithm doesn't do what he wants it to. He just doesn't know how to change the algorithm to do what he wants. So the debugger is not useful in this case. \$\endgroup\$ – BlueRaja - Danny Pflughoeft Jul 5 '11 at 7:22
  • 1
    \$\begingroup\$ @AttackingHobo @BlueRaja I agree and I've deleted my comment. That was me just leaping to conclusions about what was going on. I really do apologise for making you have to explain that and for misguiding at least one person. Honestly, you can count on me to really properly absorb the question before I leave any response next time. \$\endgroup\$ – doppelgreener Jul 8 '11 at 14:08




to this:




  • \$\begingroup\$ This sounds interesting... Do you think that ordering everything by the Y coordinate before detecting collisions could solve all of my problems? Is there any catch? \$\endgroup\$ – Vittorio Romeo Jul 10 '11 at 19:11
  • \$\begingroup\$ Aaaand I found the "catch". Using this method, the jumping bug is corrected, but if I set Velocity.Y to 0 after hitting a ceiling, it occurs again. \$\endgroup\$ – Vittorio Romeo Jul 11 '11 at 11:29
  • \$\begingroup\$ @Vee: set Position = nextPosition immediately inside the for loop, otherwise the unwanted collision resolutions (setting onGround) still occur. The player should be pushed vertically down (and never up) when hitting the ceiling thus onGround should never be set. This is how the XNA demo does it, and I cannot repro the "ceiling" bug there. \$\endgroup\$ – Leftium Jul 11 '11 at 12:25
  • \$\begingroup\$ pastebin.com/TLrQPeBU - this is my code: I actually work on the Position itself, without using a "nextPosition" variable. It should work as it does in the XNA demo, but if I keep the line that sets Velocity.Y to 0 (line 57) uncommented then the jumping bug occurs. If I remove it, the player keeps floating when jumping into a ceiling. Can this be fixed? \$\endgroup\$ – Vittorio Romeo Jul 11 '11 at 14:34
  • \$\begingroup\$ @Vee: your code doesn't show how onGround is set, so I can't investigate why jumping is incorrectly allowed. The XNA demo updates its analogous isOnGround property inside HandleCollisions(). Also, after setting Velocity.Y to 0, why does gravity not starting moving the player down, again? My guess is the onGround property is improperly set. Take a look at how the XNA demo updates previousBottom and isOnGround (IsOnGround). \$\endgroup\$ – Leftium Jul 11 '11 at 15:53


Your code would look something like this:

// collision objects
while ( StillCollidingWithSomething(object) )
  float xDistanceToResolve = XDistanceToMoveToResolveCollisions( object );
  float yDistanceToResolve = YDistanceToMoveToResolveCollisions( object );
  bool xIsColliding = (xDistanceToResolve != 0.f);


    object->Move( 0.f, yDistanceToResolve );
  else // otherwise, resolve the collision by moving along x
    object->Move( xDistanceToResolve, 0.f );


bool StillCollidingWithSomething( MovingObject object )
  // don't test 'object' against itself!)
    // it's colliding
    if ( Overlaps( collisionObject[i], object ) )
      return true;
  return false;

float XDistanceToMoveToResolveCollisions( MovingObject object )
  // return whichever move is smaller

  return minimumMove;

float FindDistanceToEmptySpaceAlongX( Vector2D position )
  Vector2D cursor = position;
  bool colliding = true;
  // until we stop colliding...
  while ( colliding )
    colliding = false;
    // loop over all collision objects...
      // and if we hit an object...
      if ( Overlaps( collisionObject[i], cursor ) )
        // move outside of the object, and repeat.
        cursor.x = collisionObject[i].rightSide;
        colliding = true;

        // our new cursor position
  return cursor.x - position.x;  



  • 1
    \$\begingroup\$ i.stack.imgur.com/NLg4j.png - this happens if I use the above method. \$\endgroup\$ – Vittorio Romeo Jul 5 '11 at 8:02
  • 1
    \$\begingroup\$ Maybe I'm not understading your code correctly, but let me explain the problem in the diagram: since the player is faster on the X axis, the X penetration is > than Y penetration. Collision chooses Y axis (because the penetration is smaller) and pushes the player vertically. This does not occur if the player is slow enough so that Y penetration is always > than X penetration. \$\endgroup\$ – Vittorio Romeo Jul 5 '11 at 13:18
  • 1
    \$\begingroup\$ @Vee Which pane of the diagram are you referring to, here, as giving an incorrect behaviour using this approach? I'm assuming pane 5, in which the player is clearly penetrating less in X than in Y, which would result in being pushed out along the X axis -- which is the correct behaviour. You only get the bad behaviour if you're selecting an axis for resolution based upon velocity (as in your image), and not based upon actual penetration (as I suggested). \$\endgroup\$ – Trevor Powell Jul 5 '11 at 22:57
  • 1
    \$\begingroup\$ @Trevor: Ah, I see what you're saying. In that case, you could simply make it if(fabs( yDistanceToResolve ) < fabs( xDistanceToResolve ) || xDistanceToResolve == 0) { object->Move( 0.f, yDistanceToResolve ); } else { object->Move( xDistanceToResolve, 0.f ); } \$\endgroup\$ – BlueRaja - Danny Pflughoeft Jul 10 '11 at 5:51
  • 1
    \$\begingroup\$ @BlueRaja Great point. I've edited my answer to use fewer conditionals, as you suggest. Thanks! \$\endgroup\$ – Trevor Powell Jul 10 '11 at 8:22


I have improved it

It seems the key thing I changed is classifying the intersections.

Intersections are either:

  • Ceiling bumps
  • Ground hits (push out of the floor)
  • Mid-air wall collisions
  • Grounded wall collisions

and I resolve them in that order





  • \$\begingroup\$ I tried your method (see my implementation: pastebin.com/HarnNnnp) but I don't know where to set the player's Velocity to 0. I tried setting it to 0 if encrY <= 0 but that lets the player stop in mid air while sliding along a wall and also lets him repeatedly wall-jump. \$\endgroup\$ – Vittorio Romeo Jul 10 '11 at 11:40
  • \$\begingroup\$ However, this works correctly when the player interacts with the spikes (as shown in the .gif). I would really appreciate if you could help me solve the wall-jumping (also getting stuck in walls) problem. Keep in mind that my walls are made of several AABB tiles. \$\endgroup\$ – Vittorio Romeo Jul 10 '11 at 11:46
  • \$\begingroup\$ Sorry for posting another comment, but after copy-pasting your code in a brand new project, changing sp to 5 and making the tiles spawn in a wall shape, the jumping bug happens (refer to this diagram: i.stack.imgur.com/NLg4j.png) \$\endgroup\$ – Vittorio Romeo Jul 10 '11 at 12:03
  • \$\begingroup\$ Ok, try it now. \$\endgroup\$ – bobobobo Jul 14 '11 at 0:38
  • \$\begingroup\$ +1 for working code sample (missing horizontally moving "spike" blocks, though :) \$\endgroup\$ – Leftium Jul 14 '11 at 4:44


My Solution:


-(engine detects possible collisions, quickly)

  • \$\begingroup\$ "(object looks at depth of penetration, as well as previous position relative to other object's previous position, to determine which side to slide out of)" this is the part I'm interested in. Can you elaborate? Does it succeed in the situation shown by the .gif and the diagram? \$\endgroup\$ – Vittorio Romeo Jul 9 '11 at 22:59
  • \$\begingroup\$ I've yet to find a situation (other than high velocities) that this method does not work in. \$\endgroup\$ – ultifinitus Jul 10 '11 at 6:00
  • \$\begingroup\$ Sounds good, but can you actually explain how do you resolve penetrations? Do you solve always on the smallest axis? Do you check the side of the collision? \$\endgroup\$ – Vittorio Romeo Jul 10 '11 at 11:25
  • \$\begingroup\$ No as a matter of fact the smaller axis is not a good (primary) way to go. IMHO. I usually resolve based on which side was previously outside of the other object's side, it's the most common. When that fails, then I check based on velocity and depth. \$\endgroup\$ – ultifinitus Jul 11 '11 at 2:51









  • \$\begingroup\$ I used to use this approach back in my Game Maker days. I can think of ways to speed it up/improve it with better searches (say a binary search on the space you traveled, although depending on the distance you went and the geometry, it maybe slower), but the main drawback of this approach is that instead of doing say one check against all possible collisions, you're doing up to whatever your change in position is checks. \$\endgroup\$ – Jeff Jul 9 '11 at 18:03
  • \$\begingroup\$ "you're doing up to whatever your change in position is checks" Sorry but what exactly does than mean? BTW of course you will use space partitioning techniques (BSP, Octree, quadtree, Tilemap etc) to speed up the game but you'll Always need to do that anyway (if the map is big), the question is not about that however but about the algorithm used to move (correctly) the player. \$\endgroup\$ – Valmond Jul 9 '11 at 19:22
  • \$\begingroup\$ @Valmond I think @Jeff means that if you player is moving 10 pixels left, you can have up to 10 different collision detections. \$\endgroup\$ – Jonathan Connell Jul 11 '11 at 11:47
  • \$\begingroup\$ If that is what he is meaning then he is right and it should be that way (who can otherwise tell if we get stopped at +6 and not +7 ?). Computers are fast, I used this on the S40 (~200mhz and a not so fast kvm) and it worked like a charm. You can always try to optimize the initial algo but that will always give you corner cases like the one the OP have. \$\endgroup\$ – Valmond Jul 11 '11 at 12:02
  • \$\begingroup\$ That's exactly what I meant \$\endgroup\$ – Jeff Jul 15 '11 at 0:37


        bool resolved = false;
        foreach (Platform p in testPlat)
            Vector2 dif = p.resolveCollision(player.getCollisionMask());

            RectangleF newPos = player.getCollisionMask();

            newPos.X -= dif.X;
            newPos.Y -= dif.Y;

                if (dif.X != 0)
                if (dif.Y != 0)
                    player.velocity.Y = 0;

                resolved = true;

        if (!resolved)
            Vector2 max = Vector2.Zero;

            foreach (Vector2 v in collisions)
                if (Math.Abs(v.X) > Math.Abs(max.X))
                    max.X = v.X;
                if (Math.Abs(v.Y) > Math.Abs(max.Y))
                    max.Y = v.Y;


            if (max.Y != 0)
                player.velocity.Y = 0;

            if (max.X != 0)
                player.velocity.X = 0;





    public Point resolveCollision(Rectangle otherRect)
        if (!isCollision(otherRect))
            return Point.Zero;

        int minOtherX = otherRect.X;
        int maxOtherX = otherRect.X + otherRect.Width;

        int minMyX = collisionMask.X;
        int maxMyX = collisionMask.X + collisionMask.Width;

        int minOtherY = otherRect.Y;
        int maxOtherY = otherRect.Y + otherRect.Height;

        int minMyY = collisionMask.Y;
        int maxMyY = collisionMask.Y + collisionMask.Height;

        int dx, dy;

        if (maxOtherX - minMyX < maxMyX - minOtherX)
            dx = (maxOtherX - minMyX);
            dx = -(maxMyX - minOtherX);

        if (maxOtherY - minMyY < maxMyY - minOtherY)
            dy = (maxOtherY - minMyY);
            dy = -(maxMyY - minOtherY);

        if (Math.Abs(dx) < Math.Abs(dy))
            return new Point(dx, 0);
            return new Point(0, dy);




  • \$\begingroup\$ I am kind of skeptical of that comment I made on it not working with thin platforms. I can't think of a reason why it wouldn't. Also if you want source, I can upload an XNA project for you \$\endgroup\$ – Jeff Jul 9 '11 at 14:35
  • \$\begingroup\$ Yeah I was just testing this out some more and it goes back to your same problem of getting stuck in the wall. It's because where the two tiles line up with each other, it tells you to move up because of the lower one, and then out (right in your case) for the upper one, effectively negating the gravity movement if your y velocity is slow enough. I'll have to look into a solution for this, I seem to remember having this problem before. \$\endgroup\$ – Jeff Jul 9 '11 at 17:11
  • \$\begingroup\$ Walls are made of 16x16 tiles. Spikes are a 16x16 tile. If I resolve on the minimum axis, the jumping bug occurs (look at the diagram). Would your "extremely hacky" solution work with the situation shown in the .gif? \$\endgroup\$ – Vittorio Romeo Jul 9 '11 at 19:11
  • \$\begingroup\$ Yep, works in mine. What's your character's size? \$\endgroup\$ – Jeff Jul 9 '11 at 20:54

It's simple.

Rewrite the spikes. It's the spikes' fault.


1. Player is outside spikes
2. Spikes move into intersection position with the player
3. Player resolves incorrectly

The problem is with step 2, not 3!!





function spikes going up:

    move spikes up

    if intersecting player:
        d = player bottom edge + spikes top edge

    end if

end function



  • \$\begingroup\$ in the extreme case where moveY fails to remove the intersection (because another wall is in the way) you can check again for intersection and either try moveX or just kill him. \$\endgroup\$ – Chris Burt-Brown Jul 27 '11 at 11:33

Your Answer

