How to Made a Collision Mask

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 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: Sample Image repl.it/@Rabbid76/PyGame-SurfaceMaskIntersect

Sample Image

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: Sample Image repl.it/@Rabbid76/PyGame-SpriteMask

Sample Image

See also Sprite mask

Collisions using masks between two images only working at a certain point

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 left of the rectangle can be specified with the keyword argument topleft. e.g.:

gun_rect = gun.get_rect(topleft = (x, y))

Read How do I detect collision in pygame? and use pygame.Rect.collidepoint to detect the collision of the gun tip (gun_rect.topleft) with the enclosing rectangle of a balloon (ballon_rect):

def check_collisions(x, y):
for i in range(num_balloons):
gun_rect = gun.get_rect(topleft = (x,y))
ballon_rect = colors[i].get_rect(topleft = (balloon_list[i] - 100, y-90))
if ballon_rect.collidepoint(gun_rect.topleft):
print(f'collision with {colors[i]}')
while running: # Game loop #
# [...]

check_collisions(x, y)

# [...]

Note, that the position of the balloon is (balloon_list[i] - 100, y-90), since you are drawing it at that position:

def draw_balloons(y):
for i in range(num_balloons):
screen.blit(colors[i], (balloon_list[i] - 100, y-90))

Can't understand how collision bit mask works

That is not how collision handling works. When two bodies are in intersection, physics engine performs logical AND operator between current's body collisionBitMask and other's body categoryBitMask:

When two physics bodies contact each other, a collision may occur.
This body’s collision mask is compared to the other body’s category
mask by performing a logical AND operation. If the result is a nonzero
value, this body is affected by the collision. Each body independently
chooses whether it wants to be affected by the other body. For
example, you might use this to avoid collision calculations that would
make negligible changes to a body’s velocity.

The source.

So the result depending on how you set categoryBitMask on those two bodies. A default value for categoryBitMask is 0xFFFFFFFF, means all bits set. So when you perform & between 0xFFFFFFFF and 0b10 or 0b01, the result would be non-zero value, thus the collision.

So for example, setting your bodies like this:

spriteA.physicsBody?.categoryBitMask = 0b01
spriteA.physicsBody?.collisionBitMask = 0b01

and

spriteB.physicsBody?.categoryBitMask = 0b10
spriteB.physicsBody?.collisionBitMask = 0b10

will give you the result you want. Also, this is probably not the exact setup you need, it is just a simple example, and you will have to change values according to your needs. In this case, spriteA will collide only with bodies which have categoryBitMask set to 0b01. Same goes for spriteB, it will collide with bodies which have categoryBitMask set to 0b10.

Also, in the case if you don't want these sprites to be able to collide with anything, simply set their collisionBitMask properties to 0.



Related Topics



Leave a reply



Submit