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
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 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
Collision between masks in pygame
The mask for the Terrain
is never set. Crate a proper Terrain
mask:
class Terrain(object):
def __init__(self, x, y):
self.x = x
self.y = y
maskSurf = pg.Surface((display_width, display_height)).convert_alpha()
maskSurf.fill(0)
pg.draw.rect(maskSurf, (160, 160, 160), (self.x, self.y, display_width, 500), 0)
self.mask = pg.mask.from_surface(maskSurf)
print(self.mask.count())
# [...]
When using pygame.mask.Mask.overlap()
, then you've to check the overlapping of the Spaceship
and the Terrain
, rather than the Terrain
and the Spaceship
.
Since the Terrain
mask is a mask of the entire screen, the offset for the overlap()
test is the position of the Spaceship
:
def check_for_collisions():
offset = (int(spaceship.x), int(spaceship.y))
collide = terrain.mask.overlap(spaceship.mask, offset)
print(offset, collide)
return collide
Minimal example: repl.it/@Rabbid76/PyGame-SurfaceMaskIntersect
See also: Mask
Pygame masks Python
A mask is created from an image. The masks are just a grid with Boolean values. One field in the mask corresponds to one pixel in the surface. If it is True
, the pixel in the corresponding image belongs to the colored sprite. If False
, the pixel in the corresponding image belongs to the background. A pygame.mask.Mask
object has no position.
The pygame.mask.Mask.overlap
method checks whether the objects overlap when they are placed on the screen. Since the objects will not be placed exactly in the same place, you need to specify the offset. See PyGame collision with masks is not working and Collision between masks in PyGame.
+---------------+
| mask 1 . |
| oy |
| . |
|... ox ...+-------------+
| | | |
| | | |
+----------|----+ |
| |
| mask 2 |
+-------------+
ox
is offset_x
oy
is offset_y
Minimal example: repl.it/@Rabbid76/PyGame-SurfaceMaskIntersect
See also: Mask
When you use pygame.sprite.Sprite
objects, you don't need to compute the offset. You can us pygame.sprite.collide_mask
, which computes the offsets from the .rect
attrbutes. See How can I made a collision mask? and Pygame mask collision
Minimal example: repl.it/@Rabbid76/PyGame-SpriteMask
See also Sprite mask
Related Topics
Putting a Simple If-Then-Else Statement on One Line
Reloading Submodules in Ipython
How to Remove Relative Shift in Matplotlib Axis
Why Do My Tkinter Widgets Get Stored as None
How to Compute the Similarity Between Two Text Documents
Print Multiple Arguments in Python
Syntax Behind Sorted(Key=Lambda: ...)
How to Read Text from the Clipboard
Difference Between Class and Instance Methods
How to Handle the Window Close Event in Tkinter
Python Pandas Insert List into a Cell
Groupby Results to Dictionary of Lists
Item Frequency Count in Python
How to Efficiently Parse Fixed Width Files
How to Blit a Png with Some Transparency Onto a Surface in Pygame