Skip to content

Instantly share code, notes, and snippets.

@nitori
Last active October 15, 2025 21:37
Show Gist options
  • Select an option

  • Save nitori/59b3c2d6a9e6f1f36e9334ea4da0f17c to your computer and use it in GitHub Desktop.

Select an option

Save nitori/59b3c2d6a9e6f1f36e9334ea4da0f17c to your computer and use it in GitHub Desktop.
simple collision example
import pygame
# direction normals
LEFT = pygame.Vector2(-1, 0)
RIGHT = pygame.Vector2(1, 0)
UP = pygame.Vector2(0, -1)
DOWN = pygame.Vector2(0, 1)
ZERO = pygame.Vector2(0, 0)
class Player:
def __init__(self, pos, speed=500):
self.image = pygame.Surface((16, 32))
self.image.fill('green')
self.speed = speed
self.rect = pygame.FRect(self.image.get_rect(center=pos))
def update(self, delta: float):
keys = pygame.key.get_pressed()
direction = pygame.Vector2(
keys[pygame.K_d] - keys[pygame.K_a],
keys[pygame.K_s] - keys[pygame.K_w],
)
if direction.length_squared() > 0:
direction.normalize_ip()
movement = direction * self.speed * delta
return movement
return ZERO
def apply_x(self, movement):
self.rect.x += movement.x
def apply_y(self, movement):
self.rect.y += movement.y
def check_collision(rect, other_rects):
collision = None
for other_rect in other_rects:
if other_rect is rect:
continue # don't collide with self
if rect.colliderect(other_rect):
# the distances between the two centers x and y
dx = other_rect.centerx - rect.centerx
dy = other_rect.centery - rect.centery
# the sum of the half widths/heights of both rects.
hw = (other_rect.width + rect.width) / 2
hh = (other_rect.height + rect.height) / 2
# calculate the overlap in both directions
overlap_x = hw - abs(dx)
overlap_y = hh - abs(dy)
# we pick the smaller overlap for this wall, to move as little as possible to get out of it.
if overlap_x < overlap_y:
normal = LEFT if dx > 0 else RIGHT
depth = overlap_x
else:
normal = UP if dy > 0 else DOWN
depth = overlap_y
# if we collide with more than one wall, we take the larger overlap.
if not collision or depth > collision[1]:
collision = normal, depth
return collision
def main():
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.Clock()
player = Player((400, 300))
WALLS = [
pygame.Rect(10, 10, 50, screen.height - 20),
]
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
return
delta = clock.tick(60) / 1000
proposal = player.update(delta)
# first try x
player.apply_x(proposal)
if hit := check_collision(player.rect, WALLS):
move_by = hit[0] * hit[1]
player.rect.x += move_by.x
# then try y
player.apply_y(proposal)
if hit := check_collision(player.rect, WALLS):
move_by = hit[0] * hit[1]
player.rect.y += move_by.y
screen.fill('black')
for wall in WALLS:
pygame.draw.rect(screen, 'white', wall)
screen.blit(player.image, player.rect)
pygame.display.flip()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment