pymike's stuff

Download BubbMan (.zip, Python source)
Download BubbMan 2 (.zip, Python source)

TUTORIAL: Rectangle Collision Correction

Note: In this tutorial, the rectangle of the moving player will simply be referred to as "player".

Formula:

Move each axis of the player individually and, if there's a collision with another rectangle, perform a one-dimensional correction following the axis's movement. This formula is not plagued by the infamous "corner-catching" glitch, which allows the player to smoothly slide over flat surfaces.

Why Use It:

It's one of the simplest correction algorithms out there and is very easy to implement.

Potential Issues:

Nothing's perfect. As you may notice, collisions are only handled when the player is moving, which, in some cases, can be problematic. Also, the ground must be static, which disallows moving platforms. (Unless the ground also uses this algorithm to handle collisions with the player, which can get messy and is not ideal in most cases)

Implementation
# move along the x axis and check for collisions
player.x += x_speed
if player.collides_with(platform):
  if x_speed > 0:
    player.right = platform.left
  if x_speed < 0:
    player.left = platform.right

# move along the y axis and check for collisions
player.y += y_speed
if player.collides_with(platform):
  if y_speed > 0:
    player.bottom = platform.top
  if y_speed < 0:
    player.top = platform.bottom
Working Example (Python + PyGame required)
# May 2010 - Rectangle Collision Correction
# Released to the Public Domain

import pygame
from pygame.locals import *

# rectangle representing the player's position and dimensions (x, y, width, height)
player_rect = Rect(0, 0, 16, 16)

# set up some rectangles for the player to collide with 
tiles = [
    Rect(0, 48, 16, 16), 
    Rect(16, 48, 16, 16),
    Rect(32, 48, 16, 16),
    Rect(48, 48, 16, 16),
    Rect(64, 48, 16, 16),
    Rect(80, 48, 16, 16),
    Rect(80, 64, 16, 16),
    Rect(128, 48, 16, 16),
    Rect(128, 64, 16, 16),
    Rect(128, 80, 16, 16),
    ]

# Move the player and handle collisions
def move_player(x_speed, y_speed):
    
    # Move the player's x axis and handle collisions
    move_axis_and_check(player_rect, x_speed, 0)
    
    # Move the player's y axis and handle collisions
    move_axis_and_check(player_rect, 0, y_speed) 

# Move a single axis and perform collision checks
def move_axis_and_check(rect, x_speed, y_speed):
    rect.x += x_speed
    rect.y += y_speed
    
    if x_speed != 0 and y_speed != 0:
        print "WARNING: Moving two axes at the same time will produce collision glitches"
  
    # loop through the tiles
    for tile in tiles:
  
        # If the player rect collides with a tile, correct the collision
        if rect.colliderect(tile):
            
            #moving right, so set right of rect to left of tile
            if x_speed > 0: 
                rect.right = tile.left
                
            #moving left, so set left of rect to right of tile
            elif x_speed < 0:
                rect.left = tile.right

            #moving down, so set bottom of rect to top of tile
            if y_speed > 0:
                rect.bottom = tile.top
            
            #moving up, so set top of rect to bottom of tile
            elif y_speed < 0:
                rect.top = tile.bottom

def main():

    # sets up pygame
    pygame.init()
    pygame.display.set_caption("Rectangle Collision Correction")
    screen = pygame.display.set_mode((320, 240))
    clock = pygame.time.Clock()
    
    # game loop
    while 1:
        
        # cap the framerate at 60 frames per second
        clock.tick(60)
        
        # handle user input
        for e in pygame.event.get():
            if e.type == QUIT or (e.type == KEYDOWN and e.key == K_ESCAPE):
                pygame.quit()
                return
        
        # move the player rect around if you press the arrow keys
        key = pygame.key.get_pressed()
        if key[K_LEFT]:
            move_player(-2, 0)
        if key[K_RIGHT]:
            move_player(2, 0)
        if key[K_UP]:
            move_player(0, -2)
        if key[K_DOWN]:
            move_player(0, 2)
        
        # Keep the player's rect inside the screen area
        player_rect.clamp_ip(screen.get_rect())
        
        # draw everything
        screen.fill((0, 0, 0))
        pygame.draw.rect(screen, (255, 255, 255), player_rect)
        for tile in tiles:
            pygame.draw.rect(screen, (100, 100, 100), tile)
        pygame.display.flip()

if __name__ == "__main__":
    main()