この記事はゲームサウンド制作 Advent Calendar 2018の13日目として参加しました。
https://adventar.org/calendars/3229
はじめに
最近Pyxel( https://github.com/kitao/pyxel/blob/master/README.ja.md )を触る機会があった。
Pyxel内でも楽曲を作ることもできるが、自作のチップチューン楽曲を組み込みたかったので音源ファイルを呼び出す形で再生する方法としてPygameを使うことに。
ゲーム中にBGMを再生したい時、BGMによってはイントロを流した後、そのイントロを除いて楽曲をループさせたいという要件は少なからずある。しかし、現時点(2018/12/13)でのPygameのpygame.mixer.musicモジュールにある関数ではそのような要件を満たすことはできなかった。
ならば作ってしまおう、ってことで作ってみた。
ちなみに、stack overflowの「Pygame Music Queue not functioning」の質問の回答コードがとても良いヒントだったのでこれを参考にした。
https://stackoverflow.com/a/52578305
サンプルコードではPyxelの 01_hello_pyxel.py をベースにしている。
実装前提は以下のとおり。
Pyxel,Pygame インストール済み
01_hello_pyxel.py の主処理は省略
サンプルコード
mp3,oggファイルの場合
1 import pygame
2 import pyxel
3
4 class MusicPlayer:
5 def __init__(self,filename):
6 pygame.mixer.init()
7 pygame.mixer.music.load(filename)
8 pygame.mixer.music.play(1) #イントロ有りで1曲丸々再生
9
10 def loop(self,time=0.0):
11 pos = pygame.mixer.music.get_pos() #再生している音楽の再生時間を取得する
12 if int(pos) == -1: #再生が終了するとposは-1を返すんだって!知らなかった!
13 pygame.mixer.music.play(-1,time) #-1を指定することでループ再生、timeの指定秒数からスタートさせる
14
15
16 class App:
17 def __init__(self):
~略~
20 self.music_player = MusicPlayer('test.mp3')
21 pyxel.run(self.update, self.draw)
22
23 def update(self):
24 self.music_player.loop(time=3.0) #time(ミリ秒まで指定可能)を指定することで指定秒数からスタートさせる
25 ~略~
28
29 def draw(self):
~略~
33 App()
wavファイルの場合
Pygameの仕様で、mp3とoggファイルは再生位置指定をすれば1つのファイルだけで済むが、wavファイルは再生位置指定ができないから、イントロ部(intro_~.wav)とループ部(main_~.wav)の2つのファイルを用意しないといけない。
1 import pygame
2 import pyxel
3
4 class MusicPlayer:
5 def __init__(self,filename):
6 self._filename = filename
7 pygame.mixer.init()
8 pygame.mixer.music.load('intro_'+self._filename) #イントロ部分のwavファイルを読み込む
9 pygame.mixer.music.play(1)
10
11 def loop(self):
12 pos = pygame.mixer.music.get_pos()
13 if int(pos) == -1:
14 pygame.mixer.music.load('main_'+self._filename) #メインループのwavファイルを読み込む
15 pygame.mixer.music.play(-1) #-1でループ再生
16
17
18 class App:
19 def __init__(self):
~略~
22 self.music_player = MusicPlayer('test.wav')
23 pyxel.run(self.update, self.draw)
24
25 def update(self):
26 self.music_player.loop()
~略~
30
31 def draw(self):
~略~
35 App()
おわりに
サンプルコードはPyxel上で動くものだが、Pygame本体でもメインループ内にloop関数を仕込めばできるはずなので、作ってみたい人は作ってみて欲しい。