Rotating Images and Handling Collision in Pygame: A Step‑by‑Step Tutorial
This tutorial demonstrates how to rotate images in Pygame, correct the rotating center, implement boundary collision detection, and enhance the animation with dynamic background colors and multiple leaf objects, providing complete code examples for each stage.
The article explains common pitfalls when rotating images in Pygame, starting with an incorrect version that rotates the original surface directly, causing the leaf image to drift off‑screen.
<code>import pygame
import sys
pygame.init()
SIZE = WIDTH, HEIGHT = 200, 400
BLACK = 0, 0, 0
angle = 1
screen = pygame.display.set_mode(SIZE)
leaf = pygame.image.load("leaf.png")
leafRect = leaf.get_rect()
leafRect = leafRect.move((WIDTH - leafRect.width) / 2, (HEIGHT - leafRect.height) / 2)
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
leaf = pygame.transform.rotate(leaf, angle)
angle += 1
screen.fill(BLACK)
screen.blit(leaf, leafRect)
pygame.display.update()
clock.tick(100)</code>To fix the drift, a new variable must store the rotated image, leaving the original surface unchanged.
<code>import pygame
import sys
pygame.init()
SIZE = WIDTH, HEIGHT = 200, 400
BLACK = 0, 0, 0
angle = 1
screen = pygame.display.set_mode(SIZE)
leaf = pygame.image.load("leaf.png")
leafRect = leaf.get_rect()
leafRect = leafRect.move((WIDTH - leafRect.width) / 2, (HEIGHT - leafRect.height) / 2)
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
newLeaf = pygame.transform.rotate(leaf, angle)
angle += 1
screen.fill(BLACK)
screen.blit(newLeaf, leafRect)
pygame.display.update()
clock.tick(100)</code>Even with a stable rotation, the leaf’s center appears to wobble because the bounding rectangle changes size after rotation. The solution is to obtain a new rect centered on the original rect.
<code>newLeaf = pygame.transform.rotate(leaf, angle)
newRect = newLeaf.get_rect(center=leafRect.center)
screen.blit(newLeaf, newRect)</code>Next, the tutorial adds simple collision detection so the leaf bounces off the window edges. The code updates the leaf’s position, checks the new rect against the screen bounds, and reverses the speed when a boundary is hit.
<code>SPEED = [1, 1]
# inside the main loop
originRect = originRect.move(SPEED[0], SPEED[1])
newLeaf = pygame.transform.rotate(originLeaf, angle)
newRect = newLeaf.get_rect()
newRect.left, newRect.top = originRect.left, originRect.top
if newRect.left <= 0 or newRect.right >= WIDTH:
SPEED[0] = -SPEED[0]
if newRect.top <= 0 or newRect.bottom >= HEIGHT:
SPEED[1] = -SPEED[1]
screen.blit(newLeaf, originRect)</code>To improve visual fidelity, the article refines the boundary handling by correcting the leaf’s position when rotation temporarily enlarges its bounding box, ensuring the bounce occurs exactly at the edge.
<code>if newRect.right > WIDTH:
originRect.left = WIDTH - newRect.width
if newRect.bottom > HEIGHT:
originRect.top = HEIGHT - newRect.height</code>Finally, a more advanced example introduces a Leaf class that manages image loading, movement, rotation, and drawing for multiple leaves. It also varies the background color based on the first leaf’s position and resets leaves that fall below the bottom edge, creating a continuous falling‑leaf effect.
<code>class Leaf(object):
def __init__(self, pos=[10,10], speed=[1,1]):
self.imageSrc = pygame.image.load("leaf.png")
self.rect = self.imageSrc.get_rect().move(pos[0], pos[1])
self.speed = speed
self.angle = 0
self.image = self.imageSrc
def move(self):
self.rect = self.rect.move(self.speed[0], self.speed[1])
new_rect = self.image.get_rect()
new_rect.left, new_rect.top = self.rect.left, self.rect.top
if new_rect.left < 0 or new_rect.right > WIDTH:
self.speed[0] = -self.speed[0]
if new_rect.right > WIDTH:
self.rect.left = WIDTH - new_rect.width
if new_rect.top > HEIGHT:
self.rect.bottom = 0
def rotate(self):
self.image = pygame.transform.rotate(self.imageSrc, self.angle)
self.angle += random.randint(1,5)
if math.fabs(self.angle) == 360:
self.angle = 0
def draw(self):
screen.blit(self.image, self.rect)
</code>By combining rotation, center correction, collision handling, dynamic backgrounds, and object‑oriented design, the tutorial provides a comprehensive guide for creating smooth, interactive animations in Pygame.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.