Pygame Mask Collision

Pygame mask collision

Your application works fine. But note, pygame.sprite.collide_mask() use the .rect and .mask attribute of the sprite object for the collision detection.

You have to update self.rect after rotating the image:

class Box(pygame.sprite.Sprite):
# [...]

def rotate(self):
self.angle += 3
new_img = pygame.transform.rotate(self.image, self.angle)
new_rect = new_img.get_rect(center=self.rect.center)

# update .rect attribute
self.rect = new_rect # <------

return new_img, new_rect

See also Sprite mask


Minimal example: Sample Image repl.it/@Rabbid76/PyGame-SpriteMask

Sample Image

import pygame

class SpriteObject(pygame.sprite.Sprite):
def __init__(self, x, y, w, h, color):
pygame.sprite.Sprite.__init__(self)
self.angle = 0
self.original_image = pygame.Surface([w, h], pygame.SRCALPHA)
self.original_image.fill(color)
self.image = self.original_image
self.rect = self.image.get_rect(center = (x, y))
self.mask = pygame.mask.from_surface(self.image )
def update(self):
self.rotate()
def rotate(self):
self.angle += 0.3
self.image = pygame.transform.rotate(self.original_image, self.angle)
self.rect = self.image.get_rect(center = self.rect.center)
self.mask = pygame.mask.from_surface(self.image )

pygame.init()
clock = pygame.time.Clock()
window = pygame.display.set_mode((400, 400))
size = window.get_size()

moving_object = SpriteObject(0, 0, 50, 50, (128, 0, 255))
static_objects = [
SpriteObject(size[0] // 2, size[1] // 3, 100, 50, (128, 128, 128)),
SpriteObject(size[0] // 4, size[1] * 2 // 3, 100, 50, (128, 128, 128)),
SpriteObject(size[0] * 3 // 4, size[1] * 2 // 3, 100, 50, (128, 128, 128))
]
all_sprites = pygame.sprite.Group([moving_object] + static_objects)
static_sprites = pygame.sprite.Group(static_objects)

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

moving_object.rect.center = pygame.mouse.get_pos()
all_sprites.update()
collide = pygame.sprite.spritecollide(moving_object, static_sprites, False, pygame.sprite.collide_mask)

window.fill((255, 0, 0) if collide else (255, 255, 255))
all_sprites.draw(window)
pygame.display.update()

pygame.quit()
exit()

pygame - mask collision not working, return always same collision point

See PyGame collision with masks. Your code can't work, because of offset = 0, 0. The offset must be the distance between the top left corners of the images:

offset = (character_x - room_x), (charcater_y - room_y)
collision = characterhitbox_mask.overlap(collisionsroom1_mask, offset)

In the example above, (room_x, room_y) is the position of the room and (character_x, character_y) is the position of the character.

Pygame mask collision. Using a transparent image as background not working

I can see 3 problems:


The position of the car is self.pos * 32 - (self.rect.width / 2, self.rect.height / 2). This is the position where the car is "blit":

screen.blit(self.rotated, self.pos * 32 - (self.rect.width / 2, self.rect.height / 2))

The position stored in the rect attribute needs to be updated with the position of the car image on the screen:

class Race_car(pygame.sprite.Sprite):
# [...]

def update(self):
# [...]

screen_pos = self.pos * 32 - (self.rect.width / 2, self.rect.height / 2)
left = round(screen_pos.x)
top = round(screen_pos.y)
self.rotated = pygame.transform.rotate(self.image, self.angle)
self.rect = self.rotated.get_rect(topleft = (left, top))

screen.blit(self.rotated, self.pos * 32 - (self.rect.width / 2, self.rect.height / 2))

For the collision detection you have calculate the offset between the car and the track:

def check_for_collisions():

offset = car.rect.x - track.rect.x, car.rect.y - track.rect.y

collide = track.mask.overlap(car.mask, offset)
print(offset, collide)
return collide

Since you are using pygame.sprite.Sprite, you can simplify the code with pygame.sprite.collide_mask():

def check_for_collisions():
collide = pygame.sprite.collide_mask(car, track)
print(collide)
return collide

In your question you mentioned:

I'm trying to use a background image(Racetrack class) that has transparent areas the car object can 'drive' in.

Mask collision detects the collision between non-transparent areas. Therefore it may be necessary to invert the background mask. Flips all of the bits in the mask with invert():

class Racetrack(pygame.sprite.Sprite):
def __init__(self, x, y, w, h):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.w = w
self.h = h
self.image = pygame.image.load('pixil mask.png')
self.mask = pygame.mask.from_surface(self.image.convert_alpha())

self.mask.invert()

self.rect = self.image.get_rect()

Pygame collision with masks

The offset parameter of the method overlap() is the relative position of the othermask in relation to the pygame.mask.Mask object.

So the offset is calculated by subtracting the coordinates of slant from the coordinates of ball:

offset_x, offset_y = (slant.rect.x - ball.rect.x), (slant.rect.y - ball.rect.y)

offset = (ball.rect.x - slant.rect.x), (ball.rect.y - slant.rect.y)
if slant.mask.overlap(ball.mask, offset):
print("hit")


When you create the mask images, then I recommend to ensure that the image has per pixel alpha format by calling .convert_alpha():

class Ball:

def __init__(self, x, y):
self.x = x
self.y = y

self.image = pygame.image.load("sball.png")
self.rect = self.image.get_rect()
self.mask = pygame.mask.from_surface(self.image.convert_alpha()) # <---
class Slant:

def __init__(self, x, y):
self.x = x
self.y = y

self.image = pygame.image.load("posslant.png")
self.rect = self.image.get_rect()
self.mask = pygame.mask.from_surface(self.image.image.convert_alpha()) # <---

Minimal example: Sample Image repl.it/@Rabbid76/PyGame-SurfaceMaskIntersect

Sample Image

See also: Mask

Pygame mask for pixel perfect collision between player sprite and platform sprites

you could check to see if the character is touching the platform ( using the mask.overlap method) and then set the velocity to 0 and gradually increase the y value until they are no longer colliding then continue with the rest of the game loop. (this is how I checked for collision but I used images instead of sprites) hope this helps.



Related Topics



Leave a reply



Submit