1

I'm trying to play the ouch sound when the object ball collides with an angryball, but the sound doesn't always play. It starts on the first collision when the two objects are on the same x or y coordinate but after that it doesn't play correctly for future collisions. Maybe it's my fault on how I manage to handle their coordinates to check for the collision?

import pygame
import os
import random

size = width, height = 750, 422
screen = pygame.display.set_mode(size)

img_path = os.path.join(os.getcwd())
background_image = pygame.image.load('background.jpg').convert()
bg_image_rect = background_image.get_rect()
pygame.mixer.pre_init(44100, 16, 2, 4096)

pygame.display.set_caption("BallGame")

class Ball(object):
    def __init__(self):
        self.image = pygame.image.load("ball.png")
        self.image_rect = self.image.get_rect()
        self.image_rect.x
        self.image_rect.y
        self.facing = 'LEFT'

    def handle_keys(self):
        key = pygame.key.get_pressed()
        dist = 5
        if key[pygame.K_DOWN] and self.image_rect.y < 321:
            self.facing = 'DOWN'
            self.image_rect.y += dist
        elif key[pygame.K_UP] and self.image_rect.y > 0:
            self.facing = 'UP'
            self.image_rect.y -= dist
        if key[pygame.K_RIGHT] and self.image_rect.x < 649:
            self.facing = 'RIGHT'
            self.image_rect.x += dist
        elif key[pygame.K_LEFT] and self.image_rect.x > 0:
            self.facing = 'LEFT'
            self.image_rect.x -= dist

    def draw(self, surface):
        if self.facing == "RIGHT":
            surface.blit(pygame.transform.flip(self.image, True, False),(self.image_rect.x,self.image_rect.y))
        elif self.facing == "DOWN":
            surface.blit(pygame.image.load("ball_down.png"),(self.image_rect.x,self.image_rect.y))
        if self.facing == "UP":
            surface.blit(pygame.image.load("ball_up.png"),(self.image_rect.x,self.image_rect.y))
        elif self.facing == "LEFT":
            surface.blit(self.image,(self.image_rect.x,self.image_rect.y))


mob_images = [pygame.image.load("image1.png").convert_alpha(),pygame.image.load("image2.png").convert_alpha(),pygame.image.load("image3.png").convert_alpha(),pygame.image.load("image4.png").convert_alpha(),pygame.image.load("image5.png").convert_alpha()]

class Angryball(pygame.sprite.Sprite):
    def __init__(self, mob_images, pos_x, pos_y):
        super(Angryball, self).__init__()
        self.mob_images = mob_images
        self.image = random.choice(self.mob_images)
        self.rect = self.image.get_rect(x=pos_x, y=pos_y)
        self.facing = 'LEFT'

    def update(self, screen):
        if self.rect.x <= 0:
            self.rect.right = screen.get_rect().width
            self.rect.top = random.randint(0, screen.get_rect().height)
            self.image = random.choice(self.mob_images)
        else:
            self.rect.move_ip(-5, 0)

pygame.init()
screen = pygame.display.set_mode((750, 422))

ball = Ball()
angryball = Angryball(mob_images , 700, random.randrange(400))
sprites = pygame.sprite.Group()
sprites.add(angryball)

clock = pygame.time.Clock()

pygame.mixer.music.load("bg_music.mp3")
pygame.mixer.music.play(-1, 0.0)
ouch = pygame.mixer.Sound("border_sound.wav")

running = True
while running:
    esc_key = pygame.key.get_pressed()
    for event in pygame.event.get():
        if esc_key[pygame.K_ESCAPE]:
            pygame.display.quit()
            pygame.quit()
            running = False

    if ball.image_rect.x == angryball.rect.x:
        ouch.play()
    if ball.image_rect.y == angryball.rect.y:
        ouch.play()


    ball.handle_keys()

    screen.blit(background_image, bg_image_rect)
    screen.blit(background_image, bg_image_rect.move(bg_image_rect.width, 0))
    bg_image_rect.move_ip(-2, 0)
    if bg_image_rect.right <= 0:
        bg_image_rect.x = 0

    sprites.update(screen)
    sprites.draw(screen)

    ball.draw(screen)
    pygame.display.update()

    clock.tick(60)
skrx
  • 19,980
  • 5
  • 34
  • 48
Shuratt
  • 89
  • 8
  • 1
    I don't have time to check out the complete program atm, but try to replace your collision detection with `if ball.image_rect.colliderect(angryball.rect):`. That checks if the rects of the two objects collide. It looks like there are more problems, but this is probably a step in the right direction. – skrx Jul 31 '18 at 18:07
  • Thank you it worked – Shuratt Aug 01 '18 at 07:25

3 Answers3

1

You need to replace these lines,

if ball.image_rect.x == angryball.rect.x:
    ouch.play()
if ball.image_rect.y == angryball.rect.y:
    ouch.play()

with this one (to check if the two rects collide):

if ball.image_rect.colliderect(angryball.rect):
    ouch.play()

The problem now is that the sound will be played every frame in which the two objects collide and therefore can become quite loud (it will be played in up to 8 channels simultaneously). Also, if all channels are occupied, the sound playback can get skipped if several objects collide in short succession.

To prevent this, you could give the Angryball a collided attribute (boolean) and set it to True after the first collision. Then reset it to False after some time interval or at the same time when you reset the position.

if ball.image_rect.colliderect(angryball.rect) and not angryball.collided:
    angryball.collided = True
    ouch.play()
skrx
  • 19,980
  • 5
  • 34
  • 48
0

As suggested, i replaced the collision detection with

if ball.image_rect.colliderect(angryball.rect):

and it worked

Shuratt
  • 89
  • 8
0

You could also check for collisions at a specific point such as:

ball.rect.collidepoint(angryball.rect.x, angryball.rect.y)

What it does is test if a point is in fact inside a rect of a sprite. I find that it works nicely, it’s simple, and clear to use and understand.

Lasutriv
  • 43
  • 8