0

I'm a newbie and following along to this tutorial to create a little endless runner in pygame. I'm finished with the code and now I want to add some polish, ie a sound that plays when the player collides with an object.

However, the code isn't working and I cannot figure out why. I've attempted tried to google it to little avail and I've implemented this suggestion and it's not working.

Here's what I have:

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        player_walk_1 = pygame.image.load('Praxislabor/assets/graphics/pig_og.png').convert_alpha()         # initialize once, "self." can get called later
        player_walk_1 = pygame.transform.scale2x(player_walk_1)
        player_walk_2 = pygame.image.load('Praxislabor/assets/graphics/pig1_og.png').convert_alpha()
        player_walk_2 = pygame.transform.scale2x(player_walk_2)
        self.player_walk = [player_walk_1, player_walk_2]
        self.player_index = 0

        self.player_jump = pygame.image.load('Praxislabor/assets/graphics/pig1_og.png').convert_alpha()
        self.player_jump = pygame.transform.scale2x(self.player_jump)

        self.image = self.player_walk[self.player_index]
        self.rect = self.image.get_rect(bottomleft = (5, 268))
        self.gravity = 0

        self.jump_sound = pygame.mixer.Sound('Praxislabor/assets/audio/jump.wav')
        self.jump_sound.set_volume(0.8)

    def player_input(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_SPACE] and self.rect.bottom >= 268:
            self.gravity = -15
            self.jump_sound.play()

    def apply_gravity(self):
        self.gravity += 1
        self.rect.y += self.gravity
        if self.rect.bottom >= 268:
            self.rect.bottom = 268

    def animation_state(self):
        if self.rect.bottom > 268:
            self.image = self.player_jump
        else:
            self.player_index += 0.1
            if self.player_index >= len(self.player_walk):
                self.player_index = 0
            self.image = self.player_walk[int(self.player_index)]

    def update(self):
        self.player_input()
        self.apply_gravity()
        self.animation_state()

class Obstacle(pygame.sprite.Sprite):
    def __init__(self,type):
        super().__init__()
        
        if type == 'bird':
            bird_frame_1 = pygame.image.load('Praxislabor/assets/graphics/birb1.png').convert_alpha()
            bird_frame_1 = pygame.transform.scale2x(bird_frame_1)
            bird_frame_1 = pygame.transform.flip(bird_frame_1, 180, 0)
            bird_frame_2 = pygame.image.load('Praxislabor/assets/graphics/birb2.png').convert_alpha()
            bird_frame_2 = pygame.transform.scale2x(bird_frame_2)
            bird_frame_2 = pygame.transform.flip(bird_frame_2, 180, 0)
            self.frames = [bird_frame_1, bird_frame_2]
            y_pos = 230

        else: 
            if type == 'box':
                box1_surface = pygame.image.load('Praxislabor/assets/graphics/box1_og.png').convert_alpha()
                box1_surface = pygame.transform.scale2x(box1_surface)
                self.frames = [box1_surface]
                y_pos = 250
        
        self.animation_index = 0
        self.image = self.frames[self.animation_index]
        self.rect = self.image.get_rect(midbottom = (randint(900,1100),y_pos))

    def animation_state(self):
        self.animation_index += 0.1
        if self.animation_index >= len(self.frames):
            self.animation_index = 0
        self.image = self.frames[int(self.animation_index)]

    def update(self):
        self.animation_state()
        self.rect.x -= 6
        self.destroy()

    def destroy(self):
        if self.rect.x <= -100:
            self.kill()

And later where the problem lies:

def display_score():
    current_time = int(pygame.time.get_ticks() / 1000) - start_time                     # get ticks as int, divide to only display smaller numbers, substract play time
    score_surface = font.render(f'Score: {current_time}', False, '#536E75')             # f string converts integer to string
    score_rect = score_surface.get_rect(topleft = (5, 5))
    screen.blit(score_surface, score_rect)
    return current_time

def collisions(player, obstacles):
    collision_sound = pygame.mixer.Sound('Praxislabor/assets/audio/collision.wav')
    if obstacles:
        for obstacle_rect in obstacles:
            if player.colliderect(obstacle_rect):
                collision_sound.play()
                return False
    return True

def collision_sprite():
    if pygame.sprite.spritecollide(player.sprite,obstacle_group,False):                     # sprite, group, boolean
        obstacle_group.empty()
        return False
    else:
        return True

The if player.colliderect(obstacle_rect) does nothing, though I tried an earlier version that didn't have the classes yet, and THEN it works.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
apostopal
  • 1
  • 1
  • im not sure how its handled in pygame, but if the play() function is not blocking, then the collision_sound object is destroyed when the collisions function returns. depending on how pygame works, you either have to keep the object alive somewhere outside the function, or spin after the call to play(), till the sound has finished. – ruff09 Sep 16 '22 at 12:35

0 Answers0