Collision Detection In Pygame By albro

In this section, we want to work a little more with rectangles and move them with the mouse and keyboard, and learn more about the Rect object.
Working with rectangles
A rectangle is a very useful object in graphics programming. The Rect class in Pygame is used to work with a rectangular area. A Rect object of the Rect class can be created by having the following:
- 4 left, top, width and height parameters
- Position and size
- An object that has the rect attribute
Rect(left, top, width, height)
Rect(pos, size)
Rect(obj)
Methods that change position or size, such as move and inflate, leave the original rectangle intact and return a new rectangle.
Other properties of the rectangle
The Rect object also has other properties that can be used to move and align the rectangle. Applying these features does not change the size of the rectangle. These features are listed below:
x, y
top, left, bottom, right
topleft, bottomleft, topright, bottomright
midtop, midleft, midbottom, midright
center, centerx, centery
Using the following five properties will change the size of the rectangle while maintaining its top left position:
size, width, height, w, h
The following code displays the features introduced above in the console:
import pygame
from pygame.locals import *
SIZE = 500, 200
RED = (255, 0, 0)
GRAY = (150, 150, 150)
pygame.init()
screen = pygame.display.set_mode(SIZE)
rect = Rect(50, 60, 200, 80)
print(f'x={rect.x}, y={rect.y}, w={rect.w}, h={rect.h}')
print(f'left={rect.left}, top={rect.top}, right={rect.right}, bottom={rect.bottom}')
print(f'center={rect.center}')
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
screen.fill(GRAY)
pygame.draw.rect(screen, RED, rect)
pygame.display.flip()
pygame.quit()
Special points
The Rect class has four side points, four middle points and a center point.

Below is the code for drawing the rectangle above:
from rect import *
pts = ('topleft', 'topright', 'bottomleft', 'bottomright','midtop', 'midright', 'midbottom', 'midleft', 'center')
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
screen.fill(GRAY)
pygame.draw.rect(screen, GREEN, rect, 4)
for pt in pts:
pos = eval('rect.'+pt)
draw_text(pt, pos)
pygame.draw.circle(screen, RED, pos, 3)
pygame.display.flip()
pygame.quit()
Horizontal and vertical alignment
In the following example, we use three keys to align the rectangle horizontally:
- L - left
- C - center
- R - right
And we use the following three other keys for the vertical alignment of the rectangle:
- T - top
- M - middle
- B - bottom

from rect import *
rect = Rect(50, 60, 200, 80)
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == KEYDOWN:
if event.key == K_l:
rect.left = 0
if event.key == K_c:
rect.centerx = width//2
if event.key == K_r:
rect.right = width
if event.key == K_t:
rect.top = 0
if event.key == K_m:
rect.centery = height//2
if event.key == K_b:
rect.bottom = height
screen.fill(GRAY)
pygame.draw.rect(screen, BLUE, rect)
pygame.display.flip()
pygame.quit()
Move the rectangle with the keyboard
The move(v) method creates a new rectangle moved by the vector v. The move_ip(v) method moves a rectangle in place. The following program moves a rectangle around using the arrow keys. The thin blue rectangle is the original rectangle, and the red rectangle is the blue rectangle that has moved. We use a dictionary to associate a motion vector for each of the 4 arrow keys. We move 5 pixels in any direction:
dir = {K_LEFT: (-5, 0), K_RIGHT: (5, 0), K_UP: (0, -5), K_DOWN: (0, 5)}

from rect import *
rect0 = Rect(50, 60, 200, 80)
rect = rect0.copy()
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == KEYDOWN:
if event.key in dir:
v = dir[event.key]
rect.move_ip(v)
screen.fill(GRAY)
pygame.draw.rect(screen, BLUE, rect0, 1)
pygame.draw.rect(screen, RED, rect, 4)
pygame.display.flip()
pygame.quit()
Change the size of the rectangle
The inflate(v) method enlarges or shrinks a rectangle by the vector v and creates a new rectangle. The inflate_ip(v) method causes a rectangle to grow or shrink in place. The following program changes the size of the rectangle using the arrow keys. The modified red rectangle is the blue rectangle.

from rect import *
rect0 = rect.copy()
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == KEYDOWN:
if event.key in dir:
v = dir[event.key]
rect.inflate_ip(v)
screen.fill(GRAY)
pygame.draw.rect(screen, BLUE, rect0, 1)
pygame.draw.rect(screen, RED, rect, 4)
pygame.display.flip()
pygame.quit()
Move the rectangle with the mouse
If the point collides with the rectangle, the rect.collidepoint(pos) function returns a Boolean value of True. We use this return value along with the mouse position to find out if the mouse has clicked inside the rectangle or not. If the click has occurred, we move the rectangle with the mouse. The variable moving is set when the mouse button is clicked inside the rectangle. This variable remains true until the button is not raised. The rectangle moves only when the mouse is clicked inside the rectangle. While the rectangle is moving, add a blue border around the rectangle as shown below:

from rect import *
moving = False
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
elif event.type == MOUSEBUTTONDOWN:
if rect.collidepoint(event.pos):
moving = True
elif event.type == MOUSEBUTTONUP:
moving = False
elif event.type == MOUSEMOTION and moving:
rect.move_ip(event.rel)
screen.fill(GRAY)
pygame.draw.rect(screen, RED, rect)
if moving:
pygame.draw.rect(screen, BLUE, rect, 4)
pygame.display.flip()
pygame.quit()
Self-propelled rectangle
The following code moves a rectangle by the amount v :
rect.move_ip(v)
It then checks the four borders of the rectangle and sets the speed at which the rectangle moves outside the application window.

from rect import *
rect = Rect(100, 50, 50, 50)
v = [2, 2]
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
rect.move_ip(v)
if rect.left < 0:
v[0] *= -1
if rect.right > width:
v[0] *= -1
if rect.top < 0:
v[1] *= -1
if rect.bottom > height:
v[1] *= -1
screen.fill(GRAY)
pygame.draw.rect(screen, RED, rect)
pygame.display.flip()
pygame.quit()
colliding points
The rect.collidepoint(p) method checks whether a rectangle collides with point p or not. In the program below, we create a hundred random points and if they are inside the rectangle, we color them red. Each time you press the R key, a hundred new random points are generated.

from rect import *
points = random_points(100)
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == KEYDOWN:
if event.key == K_r:
points = random_points(100)
screen.fill(GRAY)
pygame.draw.rect(screen, GREEN, rect, 1)
for p in points:
if rect.collidepoint(p):
pygame.draw.circle(screen, RED, p, 4, 0)
else:
pygame.draw.circle(screen, BLUE, p, 4, 0)
pygame.display.flip()
pygame.quit()
Colliding rectangles
The rect.colliderect(r) method checks whether a rectangle collides with another rectangle. In the program below, we create 50 random rectangles, and if we encounter a green rectangle, we color them red. Each time you press the R key, a hundred new random rectangles are created.

from rect import *
n = 50
rects = random_rects(n)
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == KEYDOWN:
if event.key == K_r:
rects = random_rects(n)
screen.fill(GRAY)
pygame.draw.rect(screen, GREEN, rect, 1)
for r in rects:
if rect.colliderect(r):
pygame.draw.rect(screen, RED, r, 2)
else:
pygame.draw.rect(screen, BLUE, r, 1)
pygame.display.flip()
pygame.quit()
Overlapping rectangles
The rect.colliderect(r) method checks whether a rectangle collides with another rectangle or not. If we want to know that two rectangles overlap, we have to compare both rectangles with each other. The number of comparisons increases exponentially. Each time the R key is pressed, 20 new random rectangles are generated.

from rect import *
n = 30
rects = random_rects(n)
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == KEYDOWN:
if event.key == K_r:
rects = random_rects(n)
screen.fill(GRAY)
intersecting = []
for i in range(n-1):
r0 = rects[i]
for j in range(i+1, n):
r1 = rects[j]
if r0.colliderect(r1):
intersecting.append(r0)
intersecting.append(r1)
break
for i, r in enumerate(rects):
color = RED if r in intersecting else BLUE
pygame.draw.rect(screen, color, r)
draw_text(str(i), r.topleft)
pygame.display.flip()
pygame.quit()









Comments