Some preliminary modeling
I assume all objects in your game (including the player's avatar) have a bounding rectangle.
You want not only to detect collision as a boolean result, but also determine which sides are colliding (or else you won't be able to handle the top/side cases).
Collision detection for two rectangles
Assuming a rectangle is defined by its top left and bottom right points as R(x0, y0, x1, y1) and we have two rectangles A and B,
A and B intersect if and only if
A.x0 <= B.x1 and
B.x0 <= A.x1 and
A.y0 <= B.y1 and
B.y0 <= A.y1
Now this is not enough to detect from which side the collision occured. You must take the previous positions into account to handle the collision properly.
For that, you can compute the relative positions of the two rectangles.
In the general case, you can have 3 possible status for each axis (left/middle/right and above/middle/below). Combining these 3 positions yields 9 possibilities (above left, above, above right, left, collision, right, below left, below, below right).
The 4 composite cases (above left, above right, below left and below right) are a pain to handle, so you can simply prioritize one axis (typically the X axis, so that "above" and "below" only occurs when the player's sprite is entirely above the obstacles/enemies/whatever).
In the end, you should devise a function that will return 5 possible values : left, right, above, below and collide.
The pseudo-code for this function is as follows:
position check_pos (rect a, rect b)
if (a.x1 < b.x0) return left
if (a.x0 > b.x1) return right
if (a.y1 > b.y0) return above
if (a.y0 < b.y1) return below
return collide
Now to detect a collision, you have to consider the current and next positions of your moving object. Let's say rectangle a is at position a0 with a speed va, to check collision with b we can do :
position check_collision (a0, va, b)
a1 = a0 + va // apply speed to a
current = check_pos (a0, b)
next = check_pos (a1, b)
if (next == collide) return current
return clear
this will return the side from which a will collide with b. It might return "collide" too, but that would mean that you did not handle the previous time step properly (i.e. you allowed two objects to continue moving so that they remain embedded within each other).
Naive implementation
Since some or all of your objects will be moving, it is more convenient to define your rectangles as a reference point and a (width, height) couple.
Struct Point {
int x;
int y;
Point (int x, int y) : x(x), y(y) {}
Point operator+ (const Point& p) { return Point (x+p.x, y+p.y); }
};
Struct Rectangle {
enum position { left, right, top, left, collide, clear };
Point ref;
Point size;
Rectangle (Point ref, Point size) : ref(ref), size(size) {}
Rectangle (int x, int y, int w, int h) : ref(x,y), size(w,h) {}
position check_pos (const Rectangle& rect)
{
if (ref.x+size.x < rect.ref.x ) return left;
if (ref.x > rect.ref.x+rect.size.x) return right;
if (ref.y+size.y > rect.ref.y ) return top;
if (ref.y < rect.ref.y+rect.size.y) return bottom;
return collide;
}
position check_collision (const Point velocity, const Rectangle& rect)
{
Rectangle a1 = Rectangle(ref+velocity, size);
position cur = check_pos (b);
position next = a1.check_pos (b);
if (next == collide) return cur;
return clear;
}
};
This is just pseudo-C++ off the top of my head.
Don't expect it to compile out of the box, but hopefully that should get you started.