How to Detect Collisions Between Two Rectangular Objects or Images in Pygame

How to detect collisions between two rectangular objects or images in pygame

Use pygame.Rect objects and colliderect() to detect the collision between the bounding rectangles of 2 objects or 2 images:

rect1 = pygame.Rect(x1, y1, w1, h1)
rect2 = pygame.Rect(x2, y2, w2, h2)
if rect1.colliderect(rect2):
# [...]

If you have to images (pygame.Surface objects), the bounding rectangle of can be get by get_rect(), where the location of the Surface has to be set by an keyword argument, since the returned rectangle always starts at (0, 0):

(see Why is my collision test not working and why is the position of the rectangle of the image always wrong (0, 0)?)

def game_loop():
# [...]

while running:
# [...]

player_rect = player_img.get_rect(topleft = (x, y))
for i in range(len(things_cor)):
thing_rect = things_added[i].get_rect(topleft = things_cor[i])

if player_rect.colliderect(thing_rect):
print("hit")

player(x, y)
x += x_change

for i in range(len(things_cor)):
thing_x, thing_y = things_cor[i]
things(thing_x, thing_y, things_added[i])

Use pygame.time.get_ticks() to delay the start of the game for a certain time. pygame.time.get_ticks() return the number of milliseconds since pygame.init() was called. For instance:

def game_loop():
# [...]

while running:
passed_time = pygame.time.get_ticks() # passed time in milliseconds
start_time = 100 * 1000 # start time in milliseconds (100 seconds)

# [...]

# move player
if passed_time >= start_time:
x += x_change
if x < 0:
x = 0
elif x > display_width - player_width:
x = display_width - player_width

# move things
if passed_time >= start_time:
for i in range(len(things_cor)):
things_cor[i][1] += y_change
if things_cor[i][1] > display_height:
things_cor[i][1] = random.randint(-2000, -1000)
things_cor[i][0] = random.randint(0, display_width)
things_added[i] = random.choice(thing_imgs)

things_added.append(random.choice(thing_imgs))

if len(things_added) < 6:
things_cor.append(
[random.randint(0, display_width), -10])

# draw scene and update dispaly
game_display.fill(white)
player(x, y)
for i in range(len(things_cor)):
thing_x, thing_y = things_cor[i]
things(thing_x, thing_y, things_added[i])
pygame.display.update()
clock.tick(60)

Python Pygame collision detection between objects

Use a pygame.Rect object and colliderect() to find a collision between a rectangle and an object.

pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, that always starts at (0, 0) since a Surface object has no position. The position of the rectangle can be specified by a keyword argument:

while running:
# [...]

for cb in cubes:
cb[1] += .25 # cube moves down 2 pixels
screen.blit(icon2, cb) # draw cube

icon_rect = icon2.get_rect(topleft = cb)
if cb[1] > 800 or icon_rect.colliderect(spriterect):
cb[1] = -100 # move to above screen
cb[0] = randint(1, 1000)

# [...]

However, you can simplify your code:

icon_list = [icon2, icon3, icon4, icon5]

cube_lists = [[[
randrange(screen.get_width() - icon.get_width()),
randint(-1500, -350)]
for x in range(2)]
for icon in icon_list]

running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False

keys = pygame.key.get_pressed()
spriterect.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * speed
spriterect.y = 600

screen.blit(background_image, (0, 0))
screen.blit(sprite1, spriterect)

for icon, cubes in zip(icon_list, cube_lists):
for cb in cubes:
cb[1] += .25 # cube moves down 2 pixels
screen.blit(icon, cb) # draw cube

icon_rect = icon.get_rect(topleft = cb)
if cb[1] > screen.get_height() or icon_rect.colliderect(spriterect):
cb[:] = randrange(screen.get_width() - icon.get_width()), -800

pygame.display.flip()

pygame.quit()
sys.exit()

Please note, the application loop terminates if running is False. There is no point in setting running = False and to call pygame.quit() and sys.exit() in the event loop. Let the loop run to the end and call pygame.quit() and sys.exit() after the event loop.

I'm trying to detect the collision between two moving Rects in pygame

pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, that always starts at (0, 0) since a Surface object has no position. A Surface is blit at a position on the screen. The position of the rectangle can be specified by a keyword argument. For example, the top lelft of the rectangle can be specified with the keyword argument topleft. These keyword argument are applied to the attributes of the pygame.Rect before it is returned (see pygame.Rect for a full list of the keyword arguments):

while 1:
# [...]

charrect = character.get_rect(topleft = (x, y))
enrect = enemy.get_rect(topleft = (ex, ey))
collide = pygame.Rect.colliderect(charrect, enrect)

# [...]

On the other hand you do not need the variables x, y, ex, ey at all. Use the features of the pygame.Rect objects.

Additionally read How can I make a sprite move when key is held down

Minimal example:

import pygame, sys, math, random
pygame.init()

size = width, height = 800, 600
white = 255, 255, 255
red = 255, 0, 0
clock = pygame.time.Clock()
screen = pygame.display.set_mode(size)

#character = pygame.image.load("intro_ball.gif")
character = pygame.Surface((20, 20))
character.fill((0, 255, 0))
charrect = character.get_rect(topleft = (340, 480))
#enemy = pygame.image.load("ho.png")
enemy = pygame.Surface((20, 20))
enemy.fill((255, 0, 0))
enrect = enemy.get_rect(topleft = (random.randint(0, 690), 0))
lose = False

run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False

keys = pygame.key.get_pressed()
charrect.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * 4
charrect.clamp_ip(screen.get_rect())

enrect.y += 2
if enrect.y >= 600 and lose != True:
enrect.y = 0
enrect.x = random.randint(0, 690)

collide = pygame.Rect.colliderect(charrect, enrect)
if collide:
lose = True
else:
lose = False
if lose == True:
print("lose")

screen.fill(white)
screen.blit(enemy, enrect)
screen.blit(character, charrect)
pygame.display.update()

pygame.quit()
exit()

Collision Detection Between An Image And Rectangle In Pygame?

If the collision detection doesn't work, it helps to print the rects of the involved objects each frame. You'll see that the rect of the virus is positioned at the topleft coords of the screen (0, 0) and never moves when the virus moves.

In the __init__ method you have to set the coords of the self.rect, for example by passing x and y to get_rect as the topleft or center argument:

self.rect = self.player.get_rect(topleft=(x, y))

You could also do this:

self.rect.x = x
self.rect.y = y

And when the player moves, you always have to update the rect as well. You could also do this in an update method.

class Player:
def __init__(self, x, y, image):
self.x = x
self.y = y
self.player = pygame.image.load(image)
self.rect = self.player.get_rect(topleft=(x, y))
def load(self):
screen.blit(self.player, self.rect)
def move_right(self):
self.x += 7.5
self.rect.x = self.x
def move_left(self):
self.x -= 7.5
self.rect.x = self.x
def move_up(self):
self.y -= 7.5
self.rect.y = self.y
def move_down(self):
self.y += 7.5
self.rect.y = self.y

How to collide two images in Pygame module

I recommend to use a pygame.Rect objects and colliderect() to find a collision between two Surface objects. pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, that always starts at (0, 0) since a Surface object has no position. The position of the rectangle can be specified by a keyword argument:

PlayerImg_rect   = PlayerImg.get_rect(topleft = (PlayerX, PlayerY))
targetedImg_rect = targetedImg .get_rect(topleft = (targetedX, targetedX))

if PlayerImg_rect.colliderect(targetedImg_rect):
print("hit")

Pygame collision detect with object and rect

An image by itself does not have a position. You cannot test collision between a rect and something that is not placed in the world. I would recommend to create a class Bird along with a class Pipe that will both subclass pygame.Sprite.

Pygame already has collision detection built in.

A short example

bird = Bird()
pipes = pygame.Group()
pipes.add(pipeTop)
pipes.add(pipeBottom)

while True:
if pygame.sprite.spritecollide(bird,pipes):
print "Game Over"

EDIT:

Don't be afraid of classes, you will have to use them anyways sooner or later.
If you really don't want to use sprites, you can use the birds rect and the pipe and call collide_rect to check if they overlap.

EDIT2:

an example Bird class modified from pygame docs

class Bird(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)

self.image = pygame.image.load("bird.png").convert_alpha()

# Fetch the rectangle object that has the dimensions of the image
# Update the position of this object by setting the values of rect.x and rect.y
self.rect = self.image.get_rect()

You could then add methods such as move, which will move the bird down with the force of gravity.

The same would apply for the Pipe but instead of loading an image, you can create an empty Surface, and fill it with a color.

image = pygame.Surface(width,height)
image.fill((0,200,30)

Collision on air

The collision is tested against the bounding rectangle of the image, not the area drawn on the image. Make sure the platforms and player fill almost the entire area of the pygame.Surface.

Instead of drawing the player on a transparent Surface that is much larger than the player, use the Surface created by pygame.image.load directly:

class Character(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)

self.image = pygame.image.load("TheoHillsS.png")
self.rect = self.image.get_rect(topleft = (50, 300))

self.pos = vec(50, 300)
self.vel = vec(0,0)
self.acc = vec(0,0)

# [...]


Related Topics



Leave a reply



Submit