辛苦啦~ 這次是我們系統的pygame理論學習的最後一章了,把這次的音樂播放講完了,pygame的基礎知識就全部OK了。不過作為完整的教程,只有理論講解太過枯燥了,我隨後還會加一個或更多的實踐篇系列,看需要可能也會追加真3D等額外的內容。
就像上次所說的,pygame.mixer並不適合播放長時間的音樂播放,我們要使用pygame.mixer.music。
pygame.mixer.music用來播放MP3和OGG音樂檔案,不過MP3並不是所有的系統都支援(Linux預設就不支援MP3播放),所以最好還是都用Ogg檔案,我們可以很容易把MP3轉換為Ogg檔案,自己搜一下吧。
我們使用pygame.mixer.music.load()來載入一個檔案,然後使用pygame.mixer.music.play()來播放,這裡並沒有一個類似Music這樣的類和物件,因為背景音樂一般般只要有一個在播放就好了不是麼~不放的時候就用stop()方法來停止就好了,當然很自然有類似錄影機上的pause()和unpause()方法。
音效和音樂方法總結
Sound物件:
方法名 | 作用 |
---|---|
fadeout | 淡出聲音,可接受一個數字(毫秒)作為淡出時間 |
get_length | 獲得聲音檔案長度,以秒計 |
get_num_channels | 聲音要播放多少次 |
get_volume | 獲取音量(0.0 ~ 1.0) |
play | 開始播放,返回一個Channel物件,失敗則返回None |
set_volume | 設定音量 |
stop | 立刻停止播放 |
Channels物件:
方法名 | 作用 |
---|---|
fadeout | 類似 |
get_busy | 如果正在播放,返回true |
get_endevent | 獲取播放完畢時要做的event,沒有則為None |
get_queue | 獲取佇列中的聲音,沒有則為None |
get_volume | 類似 |
pause | 暫停播放 |
play | 類似 |
queue | 將一個Sound物件加入佇列,在當前聲音播放完畢後播放 |
set_endevent | 設定播放完畢時要做的event |
set_volume | 類似 |
stop | 立刻停止播放 |
unpause | 繼續播放 |
Music物件:
方法名 | 作用 |
---|---|
fadeout | 類似 |
get_endevent | 類似 |
get_volume | 類似 |
load | 載入一個音樂檔案 |
pause | 類似 |
play | 類似 |
rewind | 從頭開始重新播放 |
set_endevent | 類似 |
set_volume | 類似 |
stop | 立刻停止播放 |
unpause | 繼續播放 |
get_pos | 獲得當前播放的位置,毫秒計 |
雖然很簡單,不過還是提供一個例程吧,這裡面音樂的播放很簡單,就是上面講過的,不過其中還有一點其他的東西,希望大家學習一下pygame中按鈕的實現方法。
介面如上,執行的時候,指令碼讀取./MUSIC下所有的OGG和MP3檔案(如果你不是Windows,可能要去掉MP3的判斷),顯示的也很簡單,幾個控制按鈕,下面顯示當前歌名(顯示中文總是不那麼方便的,如果你執行失敗,請具體參考程式碼內的註釋自己修改):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# -*- coding: utf-8 -*- # 注意檔案編碼也必須是utf-8 SCREEN_SIZE = (800, 600) # 存放音樂檔案的位置 MUSIC_PATH = "./MUSIC" import pygame from pygame.locals import * from math import sqrt import os import os.path def get_music(path): # 從資料夾來讀取所有的音樂檔案 raw_filenames = os.listdir(path) music_files = [] for filename in raw_filenames: # 不是Windows的話,還是去掉mp3吧 if filename.lower().endswith('.ogg') or filename.lower().endswith('.mp3'): music_files.append(os.path.join(MUSIC_PATH, filename)) return sorted(music_files) class Button(object): """這個類是一個按鈕,具有自我渲染和判斷是否被按上的功能""" def __init__(self, image_filename, position): self.position = position self.image = pygame.image.load(image_filename) def render(self, surface): # 家常便飯的程式碼了 x, y = self.position w, h = self.image.get_size() x -= w / 2 y -= h / 2 surface.blit(self.image, (x, y)) def is_over(self, point): # 如果point在自身範圍內,返回True point_x, point_y = point x, y = self.position w, h = self.image.get_size() x -= w /2 y -= h / 2 in_x = point_x >= x and point_x < x + w in_y = point_y >= y and point_y < y + h return in_x and in_y def run(): pygame.mixer.pre_init(44100, 16, 2, 1024*4) pygame.init() screen = pygame.display.set_mode(SCREEN_SIZE, 0) #font = pygame.font.SysFont("default_font", 50, False) # 為了顯示中文,我這裡使用了這個字型,具體自己機器上的中文字型請自己查詢 # 詳見本系列第四部分://eyehere.net/2011/python-pygame-novice-professional-4/ font = pygame.font.SysFont("simsunnsimsun", 50, False) x = 100 y = 240 button_width = 150 buttons = {} buttons["prev"] = Button("prev.png", (x, y)) buttons["pause"] = Button("pause.png", (x+button_width*1, y)) buttons["stop"] = Button("stop.png", (x+button_width*2, y)) buttons["play"] = Button("play.png", (x+button_width*3, y)) buttons["next"] = Button("next.png", (x+button_width*4, y)) music_filenames = get_music(MUSIC_PATH) if len(music_filenames) == 0: print "No music files found in ", MUSIC_PATH return white = (255, 255, 255) label_surfaces = [] # 一系列的檔名render for filename in music_filenames: txt = os.path.split(filename)[-1] print "Track:", txt # 這是簡體中文Windows下的檔案編碼,根據自己系統情況請酌情更改 txt = txt.split('.')[0].decode('gb2312') surface = font.render(txt, True, (100, 0, 100)) label_surfaces.append(surface) current_track = 0 max_tracks = len(music_filenames) pygame.mixer.music.load( music_filenames[current_track] ) clock = pygame.time.Clock() playing = False paused = False # USEREVENT是什麼?請參考本系列第二部分: # //eyehere.net/2011/python-pygame-novice-professional-2/ TRACK_END = USEREVENT + 1 pygame.mixer.music.set_endevent(TRACK_END) while True: button_pressed = None for event in pygame.event.get(): if event.type == QUIT: return if event.type == MOUSEBUTTONDOWN: # 判斷哪個按鈕被按下 for button_name, button in buttons.iteritems(): if button.is_over(event.pos): print button_name, "pressed" button_pressed = button_name break if event.type == TRACK_END: # 如果一曲播放結束,就“模擬”按下"next" button_pressed = "next" if button_pressed is not None: if button_pressed == "next": current_track = (current_track + 1) % max_tracks pygame.mixer.music.load( music_filenames[current_track] ) if playing: pygame.mixer.music.play() elif button_pressed == "prev": # prev的處理方法: # 已經播放超過3秒,從頭開始,否則就播放上一曲 if pygame.mixer.music.get_pos() > 3000: pygame.mixer.music.stop() pygame.mixer.music.play() else: current_track = (current_track - 1) % max_tracks pygame.mixer.music.load( music_filenames[current_track] ) if playing: pygame.mixer.music.play() elif button_pressed == "pause": if paused: pygame.mixer.music.unpause() paused = False else: pygame.mixer.music.pause() paused = True elif button_pressed == "stop": pygame.mixer.music.stop() playing = False elif button_pressed == "play": if paused: pygame.mixer.music.unpause() paused = False else: if not playing: pygame.mixer.music.play() playing = True screen.fill(white) # 寫一下當前歌名 label = label_surfaces[current_track] w, h = label.get_size() screen_w = SCREEN_SIZE[0] screen.blit(label, ((screen_w - w)/2, 450)) # 畫所有按鈕 for button in buttons.values(): button.render(screen) # 因為基本是不動的,這裡幀率設的很低 clock.tick(5) pygame.display.update() if __name__ == "__main__": run() |
這個程式雖然可以執行,還是很簡陋,有興趣的可以改改,比如顯示播放時間/總長度,甚至更厲害一點,滑鼠移動到按鈕上班,按鈕會產生一點變化等等,我們現在已經什麼都學過了,唯一欠缺的就是實踐而已!
所以下一次,我將開始一個實戰篇,用pygame書寫一個真正可以玩的遊戲,敬請期待~~
本次使用的幾個影象檔案打包下載(也可以自己找更帥的)。