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: repl.it/@Rabbid76/PyGame-SpriteMask
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: repl.it/@Rabbid76/PyGame-SurfaceMaskIntersect
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
Parsing Datetime Strings Containing Nanoseconds
Get Lat/Long Given Current Point, Distance and Bearing
How to Use the 'JSON' Module to Read in One JSON Object at a Time
Why Are There No ++ and -- Operators in Python
Split Text Lines in Scanned Document
Python Typeerror: Not Enough Arguments for Format String
Python Replace Single Backslash with Double Backslash
Pycharm Doesn't Recognise Installed Module
Converting Python Dict to Kwargs
Pip Installing in Global Site-Packages Instead of Virtualenv
What Does a for Loop Within a List Do in Python
List Directory Tree Structure in Python
How to Clone a Django Model Instance Object and Save It to the Database