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()