Pygame如何为不同场景更换背景音乐?

How to change background music for different scenes in Pygame?

我想获取菜单和其他场景来播放不同的音乐,但我什么也做不了。这是代码:

正在设置 pygame:

pygame.init()
screen = pygame.display.set_mode((900,600),0,32)
clock = pygame.time.Clock()
font = pygame.font.Font('freesansbold.ttf', 32)

正在设置音乐:

pygame.mixer.init() 
menuMusic = pygame.mixer.Sound("cs.mp3") 
scene1Music = pygame.mixer.Sound("ut.mp3")
                    
menu_channel = pygame.mixer.Channel(0)
scene1_channel = pygame.mixer.Channel(1)

class切换场景:

class GameState():
    def __init__(self):
        self.scene = self.menu
        
    def menu(self, event_list): 
        menu_channel.play(menuMusic, loops=-1, fade_ms=5000)    
        screen.blit(font.render("Menu", True, 'white'), (60, 150))   
   
        for event in event_list:
            if event.type == pygame.MOUSEBUTTONDOWN:
                mouse_presses = pygame.mouse.get_pressed()            
                if mouse_presses[0]:
                    self.state = self.scene1
                
    def scene1(self, event_list):
        scene1_channel.play(scene1Music, loops=-1, fade_ms=5000)
        screen.blit(font.render("This is Scene1", True, 'white'), (WIDTH/15, 150))        

主游戏循环:

game = GameState()
while True:
    event_list = pygame.event.get()  
  
    for event in event_list:
        if event.type == pygame.QUIT:
            pygame.quit() 
            sys.exit()
    
    game.scene(event_list)
    
    clock.tick(24)

现在只有当我将它们都移到开头时它才有效,尽管这不是我想要的,因为它们会同时一起玩。但是,如果我将 menu_channel.play(menuMusic, loops=-1, fade_ms=5000) 移动到菜单方法中,则不会播放任何内容。 scene1_channel.play(scene1Music, loops=-1, fade_ms=5000).

也是如此

问题是您每帧都在重新启动声音,而您应该只重新启动一次。快速而肮脏的解决方案是让你切换一个布尔值 music_started,但更好的解决方案是重新考虑你的游戏状态 class.

一个class是为了封装一个东西,但是你把所有的场景都放在一个对象里了。相反,通常定义 Scene class 并为每个场景创建子 classes。这个 class 通常应该有像 on_starton_updateon_exit 这样的方法(可能还有更多)。然后你可以确保你的场景做正确的事情。

import pygame

WIDTH, HEIGHT = 640, 480


class Scene:
    def on_start(self):
        pass

    def update(self, events, dt):
        pass

    def on_exit(self):
        pass


class Menu(Scene):
    def __init__(self, screen, scenes):
        self.scenes  = scenes
        self.screen  = screen
        self.font    = pygame.font.SysFont('freesansbold.ttf', 32)
        self.music   = pygame.mixer.Sound("cs.mp3")
        self.channel = pygame.mixer.Channel(0)

    def on_start(self):
        self.channel.play(self.music, loops=-1, fade_ms=5000)

    def update(self, events, dt):
        for event in events:
            if event.type == pygame.MOUSEBUTTONDOWN:
                left_click, *_ = pygame.mouse.get_pressed()
                if left_click:
                    return self.scenes['game']

        self.screen.blit(self.font.render("Menu", True, 'white'), (60, 150))
        return self

    def on_exit(self):
        self.channel.stop()


class Game(Scene):
    def __init__(self, screen, scenes):
        self.scenes = scenes
        self.screen = screen
        self.font = pygame.font.SysFont('freesansbold.ttf', 32)
        self.music = pygame.mixer.Sound("cs.mp3")
        self.channel = pygame.mixer.Channel(0)
        self.timer = 0

    def on_start(self):
        self.channel.play(self.music, loops=-1, fade_ms=5000)

    def update(self, events, dt):
        # Go back to menu if there hasn't been any events for 5 seconds.
        if not events:
            self.timer += dt
            if self.timer >= 5:
                return self.scenes['menu']
        else:
            self.timer = 0

        self.screen.blit(self.font.render("This is Scene1", True, 'white'), (WIDTH / 15, 150))
        return self

    def on_exit(self):
        self.channel.stop()


def main():
    pygame.init()
    screen = pygame.display.set_mode((900, 600), 0, 32)
    clock  = pygame.time.Clock()

    # All the scenes.
    scenes = {}
    scenes['menu'] = Menu(screen, scenes)
    scenes['game'] = Game(screen, scenes)

    # Start with the menu.
    scene = scenes['menu']
    scene.on_start()
    while True:
        dt = clock.tick(30) / 1000.0

        events = pygame.event.get()
        for event in events:
            if event.type == pygame.QUIT:
                return

        # Switch scenes if there is a new scene.
        new_scene = scene.update(events, dt)
        if new_scene is not scene:
            # If there is a new scene, make sure to allow the old
            # scene to exit and the new scene to start.
            scene.on_exit()
            scene = new_scene
            scene.on_start()

        pygame.display.update()


if __name__ == '__main__':
    main()