iT邦幫忙

2022 iThome 鐵人賽

DAY 13
0

此文會透過GitHub@TankMan 坦克大作戰說明,透過使用Pygame套件的mixer,播放遊戲音樂與音效程式的使用過程

初始化聲音資料以建立聲音物件

  • Game初始化遊戲時,設定遊玩模式

    class Game(PaiaGame):
        def __init__(self, user_num: int, is_manual: str, map_no: int, frame_limit: int, sound: str):
            super().__init__(user_num)
            self.game_mode = self.set_game_mode()
    
  • set_game_mode,建立遊戲的遊玩模式BattleMode,並傳入sound_path,路徑裡存放所有的遊戲音樂/音效

    GAME_DIR = path.dirname(__file__)
    SOUND_DIR = path.join(GAME_DIR, "..", "asset", "sound")
    
    class Game(PaiaGame):
        def set_game_mode(self):
            map_path = path.join(MAP_DIR, self.map_name)
            sound_path = ""
            if self.is_sound:
                sound_path = SOUND_DIR
            play_rect_area = pygame.Rect(0, 0, MAP_WIDTH, MAP_HEIGHT)
            game_mode = BattleMode(self.is_manual, map_path, self.frame_limit, sound_path, play_rect_area)
            return game_mode
    
  • set_game_mode將收到的sound_path,和呼叫get_sound_data函式獲得音效資料,傳入SoundController,建立聲音物件

    class BattleMode:
        def __init__(self, is_manual: bool, map_path: str, frame_limit: int, sound_path: str, play_rect_area: pygame.Rect):
            self.sound_path = sound_path
            self.sound_controller = SoundController(sound_path, self.get_sound_data())
    
  • get_sound_data()透過create_sounds_data函式,傳入sound_idsound_file_name建立的遊戲音效資料並回傳

    class BattleMode:
        def get_sound_data(self):
            return [create_sounds_data("shoot", "shoot.wav")
    		            , create_sounds_data("touch", "touch.wav")]
    
  • 透過create_sounds_data建立sound_controller所規範的聲音資料格式

    # SoundController
    def create_sounds_data(id: str, name: str):
        return {
            "_id": id
            , "_name": name
        }
    
  • SoundController將收到的音效路徑和音效資料建立以sound_idkeysound_folder_pathsound_file_name結合的sound_path建立的Sound物件為value

    class SoundController:
        def __init__(self, sound_path: str, sounds_data_list: list):
            self._sound_path = sound_path
            if not self._sound_path:
                return
            self._sounds_obj = {}
            pygame.mixer.init()
            for sounds_data in sounds_data_list:
                sound_data = path.join(self._sound_path, sounds_data["_name"])
                self._sounds_obj[sounds_data["_id"]] = pygame.mixer.Sound(sound_data)
    

播放音樂

  • 初始化完聲音物件SoundController後,BattleMode呼叫get_bgm_data函式獲得遊戲BGM資料,傳入SoundController.play_music,以播放遊戲背景音樂

    class BattleMode:
        def __init__(self, is_manual: bool, map_path: str, frame_limit: int, sound_path: str, play_rect_area: pygame.Rect):
            self.sound_controller.play_music(self.get_bgm_data())
    
  • get_bgm_data()透過create_bgm_data函式,傳入bgm_file_namesound_volume建立的遊戲音效資料並回傳

    class BattleMode:
        def get_bgm_data(self):
            return create_bgm_data("BGM.ogg", 0.1)
    
  • 透過create_bgm_data建立sound_controller所規範的BGM資料格式

    # SoundController
    def create_bgm_data(name: str, volume: float):
        return {
            "_name": name
            , "_volume": volume
        }
    
  • play_music首先透過pygame.mixer.init函式,初始化mixer,然後使用load函式,傳入在初始化時得到的sound_folder_pathsound_file_name結合的sound_path,來加載音樂,最後呼叫set_volume將音樂的聲音大小設為傳入的bgm_data的音量,最後使用play播放音樂並將參數傳入-1使音樂會不斷重複播放

    class SoundController:
        def play_music(self, bgm_data: dict) -> None:
            if not self._sound_path:
                return
            pygame.mixer.init()
            pygame.mixer.music.load(path.join(self._sound_path, bgm_data["_name"]))
            pygame.mixer.music.set_volume(bgm_data["_volume"])
            pygame.mixer.music.play(-1)
    

播放遊戲音效

  • create_bullet是建立子彈的函式,在建立子彈的時候,呼叫SoundControllerplay_sound函式,並傳入sound_idsound_volumeplay_time,以播放射擊音效

    class BattleMode:
        def create_bullet(self, sprites: pygame.sprite.Group):
            for sprite in sprites:
                if not sprite.is_shoot:
                    continue
                self.sound_controller.play_sound("shoot", 0.03, -1)
                init_data = create_construction(sprite.id, 0, sprite.rect.center, (13, 13))
                bullet = Bullet(init_data, rot=sprite.get_rot(), margin=2, spacing=2,
                                play_rect_area=self.play_rect_area)
                self.bullets.add(bullet)
                self.all_sprites.add(bullet)
                set_shoot(sprite, False)
    
  • play_sound以收到的sound_id_sounds_obj[key]索引獲得該Sound物件,然後透過set_volume將其音量設為收到的volume,最後使用play函式播放音效,傳入-1代表完整播完該音效

    class SoundController:
        def play_sound(self, id: str, volume: float, maz_time: int) -> None:
            if not self._sound_path:
                return
            sound_obj = self._sounds_obj[id]
            sound_obj.set_volume(volume)
            sound_obj.play(maxtime=maz_time)
    

此文範例為:

  1. 聲音物件的類別與方法完整程式碼請看 GitHub@TankMan/src/game_module/SoundController.py
  2. 使用聲音物件播放遊戲音樂與音效完整程式碼請看GitHub@TankMan/src/BattleMode.py

上一篇
讀取自製地圖建立遊戲角色程式 @TankMan
下一篇
公開!開發遊戲的所有資源
系列文
用程式寫遊戲給AI玩30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言