Collisions¶
Pygame, unlike game engines like Unity or Godot, doesn’t have concept of game
objects. Images are handled through concept of surface, a set of pixels. To
position surfaces on screen you already have used Rect objects. Besides
ability to position objects on a screen Rect also provides methods
to check various collisions.
Here you will be presented two most common types of check for collision. A
collision between Rect and a point and collision between two Rect
objects.
Point collision¶
First collision type is to check does a point collide with a rect. This is useful when you want to check for example was mouse clicked within an on object on a screen. Next you will learn how to detect mouse click within a very simple button.
Type in the following initial program and save it to the file:
import pygame as pg
pg.init()
screen = pg.display.set_mode([500, 500])
# Button (green)
button = pg.Surface((150, 80))
button.fill((0, 255, 0))
button_rect = button.get_rect(center=(250, 250))
# Pressed button
pressed_button = pg.Surface((150, 80))
pressed_button.fill((255, 0, 0))
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
exit()
draw_button = button
if pg.mouse.get_pressed()[0]:
draw_button = pressed_button
screen.fill((0, 0, 0))
screen.blit(draw_button, button_rect)
pg.display.flip()
When you run the program you see that when ever you click a mouse button color of button changes from green to red. But color changes when clicking anywhere. To change that so that color changes only when you click on the button you need to do very minimal change to the code:
@@ 21 @@
if pg.mouse.get_pressed()[0]:
- draw_button = pressed_button
+ if button_rect.collidepoint(pg.mouse.get_pos()):
+ draw_button = pressed_button
And that’s it. collidepoint method on a Rect object checks if the given
point is within the rect.
Note
Right edge and bottom edge are not considered to be inside the rect.
The following is the full code:
import pygame as pg
pg.init()
screen = pg.display.set_mode([500, 500])
# Button (green)
button = pg.Surface((150, 80))
button.fill((0, 255, 0))
button_rect = button.get_rect(center=(250, 250))
# Pressed button
pressed_button = pg.Surface((150, 80))
pressed_button.fill((255, 0, 0))
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
exit()
draw_button = button
if pg.mouse.get_pressed()[0]:
if button_rect.collidepoint(pg.mouse.get_pos()):
draw_button = pressed_button
screen.fill((0, 0, 0))
screen.blit(draw_button, button_rect)
pg.display.flip()
Colliding to another rect¶
Second collision type is to check does two Rect objects collide to each
other. This is very useful for all kind of checks for example to check if
player collided with an enemy.
This is the initial code. Type it in and save to a file:
import pygame as pg
pg.init()
screen = pg.display.set_mode([500, 500])
# Dangerzone
dangerzone = pg.Surface((150, 80))
dangerzone.fill((255, 0, 0))
dangerzone_rect = dangerzone.get_rect(center=(250, 250))
# Player
player = pg.Surface((50, 50))
player.fill((0, 0, 255))
player_rect = player.get_rect(topleft=(10, 10))
clock = pg.time.Clock()
while True:
clock.tick(30)
for event in pg.event.get():
if event.type == pg.QUIT:
exit()
keys = pg.key.get_pressed()
if keys[pg.K_w]:
player_rect.y -= 3
if keys[pg.K_a]:
player_rect.x -= 3
if keys[pg.K_s]:
player_rect.y += 3
if keys[pg.K_d]:
player_rect.x += 3
screen.fill((0, 0, 0))
screen.blit(dangerzone, dangerzone_rect)
screen.blit(player, player_rect)
pg.display.flip()
In this example you can move around by using classical WASD-keys movement. On screen you see two objects smaller blue rectangle at upper left corner and big red rectangle at middle of the screen. Blue is you - the player and red is “danger zone” which you’re not supposed to move on to. Initially you can move freely around the screen and when you go over red area nothing happens.
Now change the program to react red area in the screen and reset player position back to top left corner if player touches the red area. To achieve that do the following changes to your code:
@@ 34 @@
player_rect.left += 3
+
+ if player_rect.colliderect(dangerzone_rect):
+ player_rect.topleft = (10, 10)
The colliderect method on Rect object checks if those two rects
overlap. If they do it returns True and False if they don’t. This is
useful to check collisions between any objects.
Note
This is very simple check and doesn’t take into account shapes that are complex.
The following is the full code:
import pygame as pg
pg.init()
screen = pg.display.set_mode([500, 500])
# Dangerzone
dangerzone = pg.Surface((150, 80))
dangerzone.fill((255, 0, 0))
dangerzone_rect = dangerzone.get_rect(center=(250, 250))
# Player
player = pg.Surface((50, 50))
player.fill((0, 0, 255))
player_rect = player.get_rect(topleft=(10, 10))
clock = pg.time.Clock()
while True:
clock.tick(30)
for event in pg.event.get():
if event.type == pg.QUIT:
exit()
keys = pg.key.get_pressed()
if keys[pg.K_w]:
player_rect.top -= 3
if keys[pg.K_a]:
player_rect.left -= 3
if keys[pg.K_s]:
player_rect.top += 3
if keys[pg.K_d]:
player_rect.left += 3
if player_rect.colliderect(dangerzone_rect):
player_rect.topleft = (10, 10)
screen.fill((0, 0, 0))
screen.blit(dangerzone, dangerzone_rect)
screen.blit(player, player_rect)
pg.display.flip()
Summary¶
Congratulations! In this section you have learned how to detect collisions in two ways:
Point within a rect
Rect overlapping an another rect