2

I am trying to build a simple version of Flappy Bird. To detect collisions between my circle(Flappy Bird) and my rectangles(Pipes) I was using pygame.sprite.collide_rect() but I wanted a better way of handling collisions.

But using mask collision causes no detection of the collision. The circle passes directly through the rectangle as if it isn't there.

Here is my code:

bird_group = pygame.sprite.Group()
pipe_group = pygame.sprite.Group()

class Bird(pygame.sprite.Sprite):
    def __init__(self, x_loc, y_loc, velocity):
        super(Bird, self).__init__()
        self.velocity = velocity
        self.x_loc = x_loc
        self.y_loc = y_loc
        self.image = pygame.image.load(os.path.join(game_folder,"index2.png")).convert()
        self.image.set_colorkey(WHITE)
        self.image = pygame.transform.scale(self.image,(60,65))
        self.rect = self.image.get_rect()
        self.rect.center = (x_loc,y_loc)
    def update(self):
        self.rect.y += self.velocity
        self.velocity = self.velocity+1
        self.mask = pygame.mask.from_surface(self.image)
    def jump(self):
        self.velocity = -10
    def boundary_collison(self):
        if self.rect.bottom+100>=display_height or self.rect.top<=0:
            return True

class UpperPipe(pygame.sprite.Sprite):
    """docstring for UpperPipe"""
    def __init__(self, pipe_x, pipe_height, pipe_speed):
        super(UpperPipe, self).__init__()
        self.pipe_speed = pipe_speed
        self.image = pygame.Surface((pipe_width, pipe_height))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.x = (pipe_x)
        self.rect.y = (0)
    def update(self):
        self.rect.x -= self.pipe_speed
        self.mask = pygame.mask.from_surface(self.image)
    def x_cord(self):
        return self.rect.x

class LowerPipe(pygame.sprite.Sprite):
    """docstring for UpperPipe"""
    def __init__(self, pipe_x, pipe_height, pipe_speed):
        super(LowerPipe, self).__init__()
        self.pipe_speed = pipe_speed
        self.image = pygame.Surface((pipe_width, display_height-(pipe_gap+pipe_height)))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.x = (pipe_x)
        self.rect.y = (pipe_height+pipe_gap)
    def update(self):
        self.rect.x -= self.pipe_speed
        self.mask = pygame.mask.from_surface(self.image)
    def x_cord(self):
        return self.rect.x

The following code I use to make the sprites:

bird = Bird(x_loc,y_loc,velocity)
bird_group.add(bird)

pipe_list = []
init_pipe_x = 500
for make in range(pipe_count):
    pipe_x = init_pipe_x+((between_pipe+pipe_width)*make)
    pipe_height = (round(random.uniform(0.2,0.8), 2))*(display_height-pipe_gap)
    upper = UpperPipe(pipe_x,pipe_height,pipe_speed)
    lower = LowerPipe(pipe_x,pipe_height,pipe_speed)
    add_pipe = [upper,lower]
    pipe_list.append(add_pipe)
    pipe_group.add(upper)
    pipe_group.add(lower)

For detection inside my game loop I use the following code:

bird_hits = pygame.sprite.spritecollide(bird,pipe_group,False,pygame.sprite.collide_mask)
if bird_hits:
    gameExit = True
  • Please edit your question and provide a [minimal, **complete** and **verifiable** example](https://stackoverflow.com/help/mcve). That will make it a lot easier for us to analyze the program and to find the bugs. – skrx Jul 03 '18 at 07:42

2 Answers2

0

You haven't defined any collide_mask in your class : something like

self.mask = pygame.mask.from_surface(image) 

So if the rect of your Upper and lower pipe corresponds to the hitbix of these: simply use

bird_hits = pygame.sprite.spritecollide(bird,pipe_group,False)

or create a self.mask in your class to use

bird_hits = pygame.sprite.spritecollide(bird,pipe_group,False,pygame.sprite.collide_mask)
icetomtom
  • 25
  • 1
  • 5
0

The pygame.Surfaces that you pass to mask.from_surface must have an alpha channel. That means you either have to call the convert_alpha or the set_colorkey method of the surfaces.

class UpperPipe(pygame.sprite.Sprite):

    def __init__(self, pipe_x, pipe_height, pipe_speed):
        super(LowerPipe, self).__init__()
        self.pipe_speed = pipe_speed
        # Either call `convert_alpha` ...
        self.image = pygame.Surface((pipe_width, display_height-(pipe_gap+pipe_height))).convert_alpha()
        self.image.fill(GREEN)
        # ... or call `set_colorkey`.
        # I think surfaces converted with convert_alpha are blitted faster.
        # self.image.set_colorkey((0, 0, 0))

        # You also don't have to create the mask repeatedly in the
        # update method. Just call it once in the __init__ method.
        self.mask = pygame.mask.from_surface(self.image)
skrx
  • 19,980
  • 5
  • 34
  • 48