I wrote a tutorial here that could help: http://mijyn.github.io/tutorial/2013/06/05/platformer-aabb-cr.html
But, as StackExchange doesn't exactly love people linking tutorials, I'll give a basic overview of what it says. I was facing the challenge of not copying and pasting the entire post, but still making this answer more than just a link. I think I solved this by simply giving the concepts here, and leaving the implementation in the link.
Here are the beautiful graphics I'm using to demonstrate:
||||||||
| | <- Object 1
||||||||
--------
- - <- Object 2
--------
Alright, so, to check collision between 2 objects, you have to check the overlap between both objects:
Startpos1 Endpos1
v v
||||||||||||
| -----|--------
| - | - In this case, endpos1 > startpos2 and endpos1 < endpos2
||||||-||||| - Therefore, there is a collision.
-------------- We must also check vice versa
^ ^
Startpos2 Endpos2
We must check this on both axises, because if not, a situation like this could come up:
||||||||||
| |
||||||||||
If we only check the X axis,
---------- this will be detected as a collision.
- -
----------
To resolve, we must find the overlap, and subtract it from the axis:
++++++ Overlap = Endpos1 - Startpos2
Startpos1 Endpos1 For this to work,
v v we must make sure that Startpos1 < Startpos2
||||||||||||
| -----|--------
| - | -
||||||-||||| -
--------------
^ ^
Startpos2 Endpos2
If your game is 1D, the entire collision detection and response process is trivial: Check if there is a collision, and if so, subtract the overlap. Done!
However, chances are, your game is 2D or 3D. So, the obvious solution is to simply check each axis for collision and subtract the overlap if applicable. Also, we must make sure that both axises are colliding
Slight problem with that though:
||||||||||||
| -----|-------- Where do you think this will resolve?
| - | -
||||||-||||| -
--------------
||||||||||||
| |
| |
||||||||||||
--------------
- - Most likely not what you wanted
- -
--------------
So therefore, we must only resolve one axis if possible. We must resolve the shortest overlap. This will work for most situations. Except for this:
||||||||||||
| | -------------- Frame 1
|||||||||||| - -
--------------
||||||||||||
-------|------ |
- |||||||||||| Frame 2
--------------
Which is the shortest overlap? Y. So it'll end up like this:
||||||||||||
| |
||||||||||||
--------------
- -
--------------
Not what we want.
To fix this, we must find which axises the previous frame collided with, and resolve the collision for the other axis:
||||||||||||
| | -------------- Collides with Y
|||||||||||| - - Therefore, we must resolve X in the next frame
--------------
||||||||||||
| |
||||||||||||
-------------- Collides with none
- - Therefore, we must resolve both in the next frame
--------------
Now it should work perfectly, right? Not quite (whoever told you that AABB is easy was lying!! XD). What if this happens?
||||||||||||
| | -------------- Frame 1
|||||||||||| - -
--------------
||||||||||||
------------|- |
- ||||||||||||
-------------- Frame 2
It will resolve the X axis (awesome!), but which side?
||||||||||||
--------------| |
- -||||||||||||
--------------
Not what we want!
How do we fix this? Let's go back a bit:
++++++ Overlap = Endpos1 - Startpos2
Startpos1 Endpos1 For this to work,
v v we must make sure that Startpos1 < Startpos2
||||||||||||
| -----|--------
| - | -
||||||-||||| -
--------------
^ ^
Startpos2 Endpos2
True, we do have to make sure that Startpos1 < Startpos2. However, we must use Startpos1 from the previous frame, not this one.
Alright, so, now we have a good collision response function that should work great!
However..... (you knew this was coming, didn't you? XD) that's not the end of the story. While it works great for single objects, we might run into problems in some situations with more than one object:
------
- -
- -
------ Frame 1
||||||======
| |= =
| |= =
||||||======
------
- -
- -
||||||-- Frame 2
| ===|==
| = | =
|||||| =
======
The bottom object (the one with =) knows to resolve the X axis. However, the top one thinks that it's best to resolve the Y axis, because it doesn't know which side to resolve (none of the axises were colliding in Frame 1).
To fix this, we must sort the objects such that objects that collide with either axis with Object 1 in Frame 1 (in this example, it's the = one) are placed in front of objects that don't collide with either axis (in this example, it's the - one).
I apologize if my language style or clarity becomes worse later on in the post, I'm writing this at midnight XD