此文會透過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_id
和sound_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_id
為key
,sound_folder_path
和sound_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_name
和sound_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_path
和sound_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
是建立子彈的函式,在建立子彈的時候,呼叫SoundController
的play_sound
函式,並傳入sound_id
、sound_volume
和play_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)
此文範例為:
- 聲音物件的類別與方法完整程式碼請看 GitHub@TankMan/src/game_module/SoundController.py
- 使用聲音物件播放遊戲音樂與音效完整程式碼請看GitHub@TankMan/src/BattleMode.py