繁体   English   中英

使用 pygame 播放声音时音频失真

[英]distorted audio when playing a sound with pygame

我正在尝试用圆形和矩形制作街头霸王风格的游戏(懒得画艺术)。 但是,当我尝试播放出拳的声音时,听起来像是失真了。 我在玩家死亡时播放的 KO 音效也是如此。

这是声音

https://audio.nathanli1818.repl.co/

继承人的代码:

import pygame

pygame.init()

colors = {
    "white": (255, 255, 255),
    "black": (0, 0, 0),
    "blue": (71, 52, 237),
    "green": (53, 189, 71),
    "brown": (79, 21, 21),
    "red": (184, 39, 39),
    "purple": (145, 27, 209)

}

class Fighter:
    def __init__(self, win, x, y, win_width, win_height, color, healthx, healthy):
        self.win = win
        self.gravity = 0
        self.win_width = win_width
        self.win_height = win_height
        self.color = color
        self.health = 100
        self.healthx = healthx
        self.healthy = healthy
        self.dir_ = "right"
        self.x = x
        self.y = y

        self.base = pygame.Rect(0, 0, 70, 100)
        self.base.centerx = self.x
        self.base.centery = self.y

        self.attack_ = pygame.Rect(0, 0, 20, 20)
        self.healthbar = pygame.Rect(0, 0, self.health * 3, 20)
        self.healthbar.center = (self.healthx, self.healthy)

        self.background = pygame.Rect(0, 0, 300, 20)
        self.background.center = self.healthbar.center

        self.punch = pygame.mixer.Sound("sounds/attack.wav")
        self.punch.set_volume(0.3)

        self.KO = pygame.mixer.Sound("sounds/KO.mp3")
        self.KO.set_volume(0.3)

    def render(self):
        pygame.draw.ellipse(self.win, self.color, self.base)
        self.x = self.base.centerx
        self.y = self.base.centery

    def move(self, x, y):
        self.base.centerx = x
        self.base.centery = y

    def fall(self):
        self.base.y += self.gravity
        self.gravity += 1

        if self.base.bottom >= self.win_height - 50:
            self.gravity = 0
            self.base.bottom = self.win_height - 50

    def draw_healthbar(self):
        if self.health <= 0:
            flag = 0
            if not flag:
                self.KO.play()
                flag += 1
                self.health = 100
        
        self.healthbar.width = self.health * 3
        pygame.draw.rect(self.win, colors["red"], self.background)
        pygame.draw.rect(self.win, colors["green"], self.healthbar)

    def attack(self, type_):
        if type_ == "punch":
            flag = 0
            if self.dir_ == "right":
                if not flag:
                    self.punch.play()
                    flag += 1

                self.attack_.center = (self.base.topright[0] + 35, self.base.centery - 10)
                pygame.draw.rect(self.win, self.color, self.attack_)

            elif self.dir_ == "left":
                if not flag:
                    self.punch.play()
                    flag += 1

                self.attack_.center = (self.base.topleft[0] - 35, self.base.centery - 10)
                pygame.draw.rect(self.win, self.color, self.attack_)


class Background:
    def __init__(self, win, win_width, win_height):
        self.win = win
        self.win_width = win_width
        self.win_height = win_height

        self.sky = (self.win_width, self.win_height - 100)
        self.ground = (self.win_width, 100)
        self.platform = (220, 30)

        self.platformTop = (220, 5)
        self.platformBottom = (220, 5)

        self.sky_base = pygame.Rect(0, 0, *self.sky)
        self.ground_base = pygame.Rect(0, 0, *self.ground)
        self.ground_base.bottom = self.win_height

        self.platform_base = pygame.Rect(0, 0, *self.platform)
        self.platform_base.center = (self.win_width / 2, self.win_height / 2 + 15)

        self.platform_top = pygame.Rect(0, 0, *self.platformTop)
        self.platform_top.center = (self.platform_base.centerx, self.platform_base.top + self.platformBottom[1])

        self.platform_bottom = pygame.Rect(0, 0, *self.platformBottom)
        self.platform_bottom.center = (self.platform_base.centerx, self.platform_base.bottom - self.platformBottom[1])

    def load(self):
        pygame.draw.rect(self.win, colors["blue"], self.sky_base)
        pygame.draw.rect(self.win, colors["green"], self.ground_base)
        pygame.draw.rect(self.win, colors["brown"], self.platform_base)


class Game:
    def __init__(self):
        self.width = 900
        self.height = 500
        self.running = True
        self.attackFlag1 = 0
        self.attackFlag2 = 0
        self.fps = 60

        self.win = pygame.display.set_mode((self.width, self.height))
        self.clock = pygame.time.Clock()
        self.fighter = Fighter(self.win, 200, 450, self.width, self.height, colors["red"], 200, 50)
        self.fighter2 = Fighter(self.win, 700, 450, self.width, self.height, colors["purple"], 700, 50)
        self.background = Background(self.win, self.width, self.height)

        pygame.display.set_caption("street fighter")

    def fighter_1(self, keys):
        if keys[pygame.K_a]:
            if self.fighter.base.left <= 0:
                self.fighter.x += 10

            self.fighter.dir_ = "left"

            x = self.fighter.x
            self.fighter.move(x - 10, self.fighter.y)

        if keys[pygame.K_d]:
            if self.fighter.base.right >= self.width:
                self.fighter.x -= 10

            self.fighter.dir_ = "right"

            x = self.fighter.x
            self.fighter.move(x + 10, self.fighter.y)

        if keys[pygame.K_w] and self.fighter.base.bottom == 450:
            self.fighter.gravity = -20

        if keys[pygame.K_s] and self.fighter.base.bottom != 450:
                self.fighter.gravity += 10

        if self.background.platform_top.colliderect(self.fighter.base):
            if keys[pygame.K_w]:
                self.fighter.gravity = -20

            else:
                self.fighter.gravity = 0
                self.fighter.base.bottom = self.background.platform_top.bottom

        if self.background.platform_bottom.colliderect(self.fighter.base):
            self.fighter.gravity += 5

        if keys[pygame.K_e]:
            self.fighter.attack("punch")

        if self.fighter.base.colliderect(self.fighter2.attack_):
            if self.attackFlag2 == 0:
                self.fighter.health -= 5
                self.attackFlag2 += 1


    def fighter_2(self, keys):
        if keys[pygame.K_LEFT]:
            if self.fighter2.base.left <= 0:
                self.fighter2.x += 10

            self.fighter2.dir_ = "left"

            x = self.fighter2.x
            self.fighter2.move(x - 10, self.fighter2.y)

        if keys[pygame.K_RIGHT]:
            if self.fighter2.base.right >= self.width:
                self.fighter2.x -= 10

            self.fighter2.dir_ = "right"

            x = self.fighter2.x
            self.fighter2.move(x + 10, self.fighter2.y)

        if keys[pygame.K_UP] and self.fighter2.base.bottom == 450:
            self.fighter2.gravity = -20

        if keys[pygame.K_DOWN] and self.fighter2.base.bottom != 450:
                self.fighter2.gravity += 10

        if self.background.platform_top.colliderect(self.fighter2.base):
            if keys[pygame.K_UP]:
                self.fighter2.gravity = -20

            else:
                self.fighter2.gravity = 0
                self.fighter2.base.bottom = self.background.platform_top.bottom

        if self.background.platform_bottom.colliderect(self.fighter2.base):
            self.fighter2.gravity += 5

        if self.fighter2.base.colliderect(self.fighter.attack_):
            if self.attackFlag1 == 0:
                self.fighter2.health -= 50
                self.attackFlag1 += 1

        if keys[pygame.K_RSHIFT]:
            self.fighter2.attack("punch")


    def run(self):
        while self.running:
            self.clock.tick(self.fps)
            self.background.load()

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.running = False

                if event.type == pygame.KEYUP:
                    if event.key == pygame.K_e:
                        self.fighter.attack_.y = 1000
                        self.attackFlag1 = 0

                if event.type == pygame.KEYUP:
                    if event.key == pygame.K_RSHIFT:
                        self.fighter2.attack_.y = 1000
                        self.attackFlag2 = 0

            keys = pygame.key.get_pressed()

            self.fighter_1(keys)
            self.fighter.fall()
            self.fighter.draw_healthbar()
            self.fighter.render()

            self.fighter_2(keys)
            self.fighter2.fall()
            self.fighter2.draw_healthbar()
            self.fighter2.render()

            pygame.display.update()

        pygame.quit()

if __name__ == '__main__':
    Game().run()

在 python 3.8.8

您的问题来自声音在其自身之上多次播放的事实。 发生这种情况是因为每一帧,您检查pygame.K_e是否被保持,如果是则播放声音。 但是,当您按下一个键时,您可能会按住该键超过一帧,因此这会导致声音在其自身之上快速连续播放多次。

解决问题的一种方法是使用pygame.mixer.Channel播放声音,它只允许在任何时候播放一种声音:

# Get a reference to a pygame channel
self.channel = pygame.mixer.Channel(0)
# Load punch sound effect
self.punch = pygame.mixer.Sound("sounds/attack.wav")

# ...

# Play using channel
self.channel.play(self.punch)

也就是说,这实际上可能不是您想要的 - 相反,您可能应该检查“键释放”事件,而不是仅检查 E 键是否保留在您的fighter_*函数中。 这将在呼叫attack之间留出足够的时间,以防止您听到的失真发生。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM