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 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
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
How to Copy Over an Excel Sheet to Another Workbook in Python
Python Ftp Implicit Tls Connection Issue
How to Escape Curly-Brackets in F-Strings
How to Rotate Selenium Webrowser Ip Address
Can Anyone Explain Python's Relative Imports
Why Do Many Examples Use 'Fig, Ax = Plt.Subplots()' in Matplotlib/Pyplot/Python
List Comprehension and Lambdas in Python
Python - Activate Conda Env Through Shell Script
Pandas Filling Missing Dates and Values Within Group
How to Call Setattr() on the Current Module
Python (And Python C API): _New_ Versus _Init_
Operationalerror: Database Is Locked
How Do Python Functions Handle the Types of Parameters That You Pass In