Pygame:声音只播放8次,然后关闭4次,然后打开,然后关闭,然后再打开

Posted

技术标签:

【中文标题】Pygame:声音只播放8次,然后关闭4次,然后打开,然后关闭,然后再打开【英文标题】:Pygame: sound only playing 8 times, then off 4 times, then on, then off, then back on 【发布时间】:2015-10-23 17:36:55 【问题描述】:

我有一个奇怪的现象,我的声音文件播放 8 次,然后关闭,然后播放,然后关闭,然后再次播放。

import sys, pygame, os, time

# Force static position of screen
os.environ['SDL_VIDEO_CENTERED'] = '1'

# to get rid of sound lag
pygame.mixer.pre_init(44100, -16, 8, 2048)

# Runs imported module
pygame.init()

# Constants
UP = 'up'
DOWN = 'down'
BOOSTSP = 12
NORMSP = 8

WIN_W = 920
WIN_H = 570
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)

PADDLE_HEIGHT = 440
BALL_WIDTH = BALL_HEIGHT = 20

class Entity(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)

class Paddle(Entity):
    def __init__(self, x, y):
        Entity.__init__(self)
        self.x = x
        self.y = y
        self.speed = 8
        self.pWidth = 20
        self.score = 0
        self.pHeight = PADDLE_HEIGHT
        self.paddle = pygame.Surface((self.pWidth, self.pHeight))
        self.paddle = self.paddle.convert()
        self.lp_moveUP = self.lp_moveDOWN = self.rp_moveUP = self.rp_moveDOWN = False

    def update(self, down, up):
        # Adjust speed
        if up or down or up or down:
            if up:
                self.y -= self.speed
            if down:
                self.y += self.speed

        # paddle movement
        if self.y < 0:
            self.y = 0
        if self.y > WIN_H - self.pHeight:
            self.y = WIN_H - self.pHeight

class Ball(Entity):
    def __init__(self, x, y):
        Entity.__init__(self)
        self.speed = [-5, -5]
        self.ball = pygame.Surface((BALL_WIDTH, BALL_HEIGHT))
        self.ball = self.ball.convert()
        self.rect = pygame.Rect(WIN_W/2, WIN_H/2-(BALL_HEIGHT/2), BALL_WIDTH, BALL_HEIGHT)

    def restart(self, lPaddle, rPaddle, screen):
        time.sleep(2)
        self.rect.y = WIN_H/2-(BALL_HEIGHT/2)
        self.rect.x = WIN_W/2
        lPaddle.y = (WIN_H/2) - (PADDLE_HEIGHT/2)
        rPaddle.y = (WIN_H/2) - (PADDLE_HEIGHT/2)

        return True

请注意,在“更新”方法中,如果球击中球拍,我会播放声音。您可以看到我打印了“playSound”函数的返回值,它是 play() 方法的返回值。

    def update(self, lPaddle, rPaddle, sound, playSound):
        # If ball hits the top or bottom
        if self.rect.top < 0 or self.rect.top > WIN_H - BALL_HEIGHT:
            self.speed[1] = -self.speed[1]
            print playSound(sound["bop"], 1)

        # If ball hits paddle
        if(self.speed[0] < 0):
            if (self.rect.left > lPaddle.x + lPaddle.pWidth - 15 and self.rect.left < lPaddle.x + lPaddle.pWidth-10) and (self.rect.top > lPaddle.y and self.rect.top < (lPaddle.y + lPaddle.pHeight)):
                self.speed[0] = -self.speed[0]
                print playSound(sound["beep"], 1)
        else:
            if (self.rect.left > rPaddle.x - 15 and self.rect.left < rPaddle.x - 5) and (self.rect.top > rPaddle.y and self.rect.top < (rPaddle.y + rPaddle.pHeight)):
                self.speed[0] = -self.speed[0]
                print playSound(sound["beep"], 1)

        self.rect = self.rect.move(self.speed)


# Returns True for .5 seconds, then False for .5 seconds.
def checkTime(cur, beg):
    return (cur - beg) % 1000 < 500


# Takes in string, (x, y) and size. Returns text and rect.
def txtRect(sen, xpos, ypos, size):
    phrase = pygame.font.Font(None, size)
    phrase = phrase.render(sen, 1, BLACK)
    phraseRect = phrase.get_rect()
    phraseRect.x = xpos
    phraseRect.y = ypos

    return phrase, phraseRect


# Loads sound files
def playSound(sound, volume):
    sound.set_volume(volume)
    return sound.play()


# Loads sound files
def loadSound():
    sound = 
    sound["beep"] = pygame.mixer.Sound("sound/beep.ogg")
    sound["boom"] = pygame.mixer.Sound("sound/boom.ogg")
    sound["bop"] = pygame.mixer.Sound("sound/bop.ogg")
    sound["choose"] = pygame.mixer.Sound("sound/choose.ogg")
    sound["count"] = pygame.mixer.Sound("sound/count.ogg")
    sound["end"] = pygame.mixer.Sound("sound/end.ogg")
    sound["music"] = pygame.mixer.Sound("sound/music.ogg")
    sound["select"] = pygame.mixer.Sound("sound/select.ogg")

    return sound


def main():
    size = WIN_W, WIN_H
    fps = 60

    # Used for count down
    countDown = 3
    decrement = True

    pygame.display.set_caption('Pong')
    screen = pygame.display.set_mode(size, pygame.SRCALPHA)

    # Create our objects
    ball = Ball((WIN_W/2)-(BALL_WIDTH/2), WIN_H/2-(BALL_HEIGHT/2))
    lPaddle = Paddle(WIN_W/15, (WIN_H/2)-(PADDLE_HEIGHT/2))
    rPaddle = Paddle(WIN_W/1.1, (WIN_H/2)-(PADDLE_HEIGHT/2))

    # Create sound objects
    sound = loadSound()

    clock = pygame.time.Clock()

    beg_time = pygame.time.get_ticks()
    intro = count = play = outro = True
    lp_moveUP = lp_moveDOWN = rp_moveDOWN = rp_moveUP = False

    while intro:
        # Print background
        screen.fill(WHITE)

        # Title Text: Pong
        text = txtRect("Pong", 0, 0, 200)
        text = txtRect("Pong", WIN_W/2-(text[1].width/2), WIN_H/4, 200)
        screen.blit(text[0], text[1])

        # Blinking Text: Click here to start
        text = txtRect("- Click here to start -", 0, 0, 50)
        text = txtRect("- Click here to start -", WIN_W/2-(text[1].width/2), WIN_H/1.7, 50)
        if checkTime(beg_time, pygame.time.get_ticks()):
            screen.blit(text[0], text[1])

        # Checks if window exit button pressed
        for event in pygame.event.get():
            if event.type == pygame.QUIT: sys.exit()
            elif event.type == pygame.MOUSEBUTTONDOWN or pygame.key.get_pressed()[pygame.K_RETURN] != 0:
                screen.blit(text[0], text[1])
                pygame.display.flip()
                playSound(sound["select"], .3)
                pygame.time.wait(1500)
                intro = False

        # Limits frames per iteration of while loop
        clock.tick(fps)
        # Writes to main surface
        pygame.display.flip()

    # Gameplay
    while play:
        # Print background
        screen.fill(WHITE)
        screen.blit(lPaddle.paddle, (lPaddle.x, lPaddle.y))
        screen.blit(rPaddle.paddle, (rPaddle.x, rPaddle.y))
        screen.blit(ball.ball, ball.rect)

        # Print Score
        sen = "Player 1 score: " + str(lPaddle.score)
        text = txtRect(sen, WIN_W/6.5, WIN_H/57, 40)
        screen.blit(text[0], text[1])
        sen = "Player 2 score: " + str(rPaddle.score)
        text = txtRect(sen, WIN_W - WIN_W/6.5 - text[1].width, WIN_H/57, 40)
        screen.blit(text[0], text[1])

        # Countdown
        if count:
            text = txtRect(str(countDown), 0, 0, 75)
            text = txtRect(str(countDown), WIN_W/3.5 - (text[1].width/2), WIN_H/4, 75)
            screen.blit(text[0], text[1])
            text = txtRect(str(countDown), WIN_W/1.4 - (text[1].width/2), WIN_H/4, 75)
            screen.blit(text[0], text[1])

            # Writes to main surface
            pygame.display.flip()

            playSound(sound["count"], 1)
            time.sleep(1)
            countDown -= 1

            # bug fix: prevent display of 0.
            if countDown == 0:
                count = False

        # Gameplay
        else:
            # Checks if window exit button pressed
            for event in pygame.event.get():
                if event.type == pygame.QUIT: sys.exit()

                # Keyboard mechanics
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        pygame.quit()
                        sys.exit()
                    if event.key == pygame.K_UP:
                        rp_moveUP = True
                        rp_moveDOWN = False

                    elif event.key == pygame.K_DOWN:
                        rp_moveUP = False
                        rp_moveDOWN = True
                    if event.key == pygame.K_w:
                        lp_moveUP = True
                        lp_moveDOWN = False

                    elif event.key == pygame.K_s:
                        lp_moveUP = False
                        lp_moveDOWN = True

                elif event.type == pygame.KEYUP:
                    if event.key == pygame.K_UP:
                        rp_moveUP = False
                    elif event.key == pygame.K_DOWN:
                        rp_moveDOWN = False
                    if event.key == pygame.K_w:
                        lp_moveUP = False
                    elif event.key == pygame.K_s:
                        lp_moveDOWN = False

            lPaddle.update(lp_moveDOWN, lp_moveUP)
            rPaddle.update(rp_moveDOWN, rp_moveUP)
            ball.update(lPaddle, rPaddle, sound, playSound)

            # If ball moves off the screen
            if ball.rect.left < 0 - ball.rect.width or ball.rect.left > WIN_W + ball.rect.width:
                if ball.rect.left < 0:
                    rPaddle.score += 1
                elif ball.rect.left > WIN_H + ball.rect.width:
                    lPaddle.score += 1
                playSound(sound["end"], 1)
                count = ball.restart(lPaddle, rPaddle, screen)
                countDown = 3

        # Game ends
        if lPaddle.score == 3 or rPaddle.score == 3:
            playSound(sound["boom"], 1)
            break

        # Limits frames per iteration of while loop
        clock.tick(fps)
        # Writes to main surface
        pygame.display.flip()

    # Gameplay
    while outro:
        # Print background
        screen.fill(WHITE)

        # End Text: Player wins
        if lPaddle.score == 3 or rPaddle.score == 3:
            if lPaddle.score == 3:
                sen = "Player 1 Wins!"
            else:
                sen = "Player 2 Wins!"

            text = txtRect(sen, 0, 0, 40)
            text = txtRect(sen, WIN_W/2-(text[1].width/2)-130, WIN_H/4, 100)

        screen.blit(text[0], text[1])

        text = txtRect("- Click here to continue -", 0, 0, 50)
        text = txtRect("- Click here to continue -", WIN_W/2-(text[1].width/2), WIN_H/1.7, 50)
        # Blinking Text: Click here to start
        if checkTime(beg_time, pygame.time.get_ticks()):
            screen.blit(text[0], text[1])

        # Checks if window exit button pressed
        for event in pygame.event.get():
            if event.type == pygame.QUIT: sys.exit()
            elif event.type == pygame.MOUSEBUTTONDOWN or pygame.key.get_pressed()[pygame.K_RETURN] != 0:
                screen.blit(text[0], (WIN_W/2-(text[1].width/2), WIN_H/1.7))
                pygame.display.flip()
                loadSound("choose", 1)
                pygame.time.wait(1500)
                outro = False
                main()

        # Limits frames per iteration of while loop
        clock.tick(fps)
        # Writes to main surface
        pygame.display.flip()

if __name__ == "__main__":
    main()

当我玩游戏时,前奏会响起,然后当球从球拍上弹起时,程序只播放 8 次,每次我玩游戏时结果完全相同。这是我的输出。任何帮助将非常感激。

/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /Users/DanielLee/PycharmProjects/newPong/pong7_sound.py

通道对象位于 0x1002c42e8

通道对象位于 0x1002c42e8

通道对象位于 0x1002c42e8

通道对象位于 0x1002c42e8

通道对象位于 0x1002c42e8

通道对象位于 0x1002c42e8

通道对象位于 0x1002c42e8

通道对象位于 0x1002c42e8

通道对象位于 0x1002c42e8

通道对象位于 0x1002c42e8

通道对象位于 0x1002c42e8

【问题讨论】:

【参考方案1】:

我认为声音在播放然后不播放的原因与重复使用的频道有关。解决方案是为声音设置一个“最大时间”,将其关闭并释放通道供以后使用。

来自文档:play(loops=0, maxtime=0, fade_ms=0)

从 play() 的文档中可以看出,第二个参数是“maxtime”,可以设置它以确保频道可用。

我对它的工作原理没有清楚的了解,即使我对错误的理解是有效的,所以任何澄清都将不胜感激。

【讨论】:

以上是关于Pygame:声音只播放8次,然后关闭4次,然后打开,然后关闭,然后再打开的主要内容,如果未能解决你的问题,请参考以下文章

在 pygame Windows 中播放声音的问题

播放和停止声音(2 次观看)

Jquery 只播放一次声音

Flash AS2 一次发出一种声音

只播放一次声音 Jquery

Sound Pool 只播放一次声音