辛苦啦~ 这次是我们系统的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书写一个真正可以玩的游戏,敬请期待~~