首页 > 解决方案 > Play sound when objects collide

问题描述

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)

标签: pythonpython-3.xpygamevirtualboxubuntu-18.04

解决方案


您需要替换这些行,

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

用这个(检查两个矩形是否碰撞):

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

现在的问题是声音会在两个物体碰撞的每一帧中播放,因此会变得非常响亮(它将同时在多达 8 个通道中播放)。此外,如果所有通道都被占用,如果多个对象连续发生碰撞,声音播放可能会被跳过。

为了防止这种情况,您可以提供Angryballacollided属性(布尔值)并将其设置为True第一次碰撞后。然后False在一段时间间隔后或在您重置位置的同时将其重置。

if ball.image_rect.colliderect(angryball.rect) and not angryball.collided:
    angryball.collided = True
    ouch.play()

推荐阅读