pycoode 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pycoode-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,221 @@
1
+ Metadata-Version: 2.4
2
+ Name: pycoode
3
+ Version: 1.0.0
4
+ Summary: 让做游戏像写一行代码一样简单 —— 基于 pygame 的极简 2D 游戏开发包
5
+ Author: pycoode
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/pycoode/pycoode
8
+ Project-URL: Documentation, https://github.com/pycoode/pycoode#readme
9
+ Keywords: game,pygame,2d,easy,beginner
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Education
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Games/Entertainment
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: pygame>=2.0
19
+
20
+ # pycoode
21
+
22
+ **让做游戏像写一行代码一样简单。**
23
+
24
+ `pycoode` 是基于 pygame 的极简 2D 游戏开发包。它替你扛下了所有麻烦事:
25
+ 窗口创建、中文字体、高 DPI、分辨率适配、游戏循环、输入、精灵、音效、场景管理。
26
+ 你只需要写游戏逻辑。
27
+
28
+ ## 特性
29
+
30
+ - **一行起跑** —— `pc.run()` 直接弹窗口;`pc.run(draw=...)` 就能画出东西
31
+ - **零适配问题** —— 游戏按设计分辨率(如 800x600)写坐标,窗口任意拉伸自动信箱缩放、不变形不错位;Windows 高 DPI(150% 缩放)自动适配
32
+ - **中文开箱即用** —— 自动匹配系统中文字体,`g.text("你好")` 不用准备字体文件
33
+ - **输入超简单** —— `g.key_held("space")`、`g.mouse_pressed(1)`,支持方向键/WASD/触屏
34
+ - **精灵系统** —— 移动、旋转、缩放、翻转、矩形/圆形碰撞、逐帧动画,`Sprite.solid("red", 50, 50)` 没有美术素材也能开工
35
+ - **音效一行播放** —— `pc.play("hit.wav")`、`pc.music("bgm.mp3")`,无声环境自动降级不崩溃
36
+ - **场景管理** —— 菜单 / 关卡 / 结算各自一个类,`self.switch(...)` 秒切换
37
+ - **跨平台** —— Windows / macOS / Linux,Python 3.8+
38
+
39
+ ## 安装
40
+
41
+ ```bash
42
+ pip install pygame pycoode
43
+ ```
44
+
45
+ ## 30 秒上手
46
+
47
+ **第 1 行代码:**
48
+
49
+ ```python
50
+ import pycoode as pc
51
+
52
+ pc.run(draw=lambda g: g.text("Hello, pycoode!", 400, 300, size=48,
53
+ color="gold", center=True))
54
+ ```
55
+
56
+ **一个能玩的小游戏(键盘控制 + 碰撞 + 计分):**
57
+
58
+ ```python
59
+ import pycoode as pc
60
+
61
+ player = pc.Sprite.solid("cyan", 48, 48, 400, 520)
62
+ coins, score = [], 0
63
+
64
+ def update(g, dt):
65
+ global score
66
+ dx = int(g.key_held("right")) - int(g.key_held("left"))
67
+ player.x = pc.clamp(player.x + dx * 420 * dt, 24, 776)
68
+ if pc.chance(dt * 3):
69
+ coins.append(pc.Sprite.solid("gold", 22, 22, pc.rand(30, 770), -20))
70
+ for c in coins:
71
+ c.y += 260 * dt
72
+ if player.collides_with(c):
73
+ c.kill(); score += 1
74
+ coins[:] = [c for c in coins if c.alive and c.y < 640]
75
+
76
+ def draw(g):
77
+ g.clear("dark")
78
+ for c in coins: c.draw(g)
79
+ player.draw(g)
80
+ g.text(f"得分 {score}", 16, 14, size=28, color="white")
81
+
82
+ pc.run(update=update, draw=draw, title="接金币")
83
+ ```
84
+
85
+ **内置演示**(安装后直接玩):
86
+
87
+ ```python
88
+ import pycoode
89
+ pycoode.demo()
90
+ ```
91
+
92
+ ## API 速查
93
+
94
+ ### 入口
95
+
96
+ | 写法 | 作用 |
97
+ |---|---|
98
+ | `pc.run()` | 弹出 800x600 窗口,ESC 退出 |
99
+ | `pc.run(update=f, draw=g)` | 带逻辑和绘制 |
100
+ | `pc.run(scene=Menu())` | 用场景管理 |
101
+ | `pc.run(width=960, height=640, title="...", fps=60, background="dark")` | 常用参数 |
102
+ | `pc.run(size="hd")` | 预设窗口大小:`small/md/large/square/hd/fullhd`,也可 `size=(1280,720)` |
103
+ | `pc.run(fit_screen=True)` | 窗口自动收缩到你的屏幕内(小笔记本不怕超出屏幕) |
104
+ | `pc.run(fullscreen=True, show_fps=True)` | 全屏 / 显示 FPS |
105
+ | `pc.run(mouse_visible=False)` | 隐藏鼠标指针 |
106
+ | `pc.run(icon="icon.png")` | 窗口图标 |
107
+
108
+ ### 窗口控制(运行时)
109
+
110
+ | 写法 | 作用 |
111
+ |---|---|
112
+ | `g.toggle_fullscreen()` | 全屏/窗口切换(快捷键 **F11** 已内置) |
113
+ | `g.set_window_size(1024, 768)` | 随时改窗口大小,游戏画面自动缩放适配,逻辑不用动 |
114
+ | `g.screen_size` | 当前真实窗口像素大小,如 `(1280, 720)` |
115
+ | `g.set_mouse_visible(False)` | 随时隐藏/显示鼠标 |
116
+ | `g.width, g.height` | 游戏设计分辨率(画布大小,永远不变) |
117
+
118
+ ### 输入(都接受 "space"/"a"/"up" 等名字)
119
+
120
+ | 写法 | 作用 |
121
+ |---|---|
122
+ | `g.key_held("right")` | 按住中 |
123
+ | `g.key_pressed("space")` | 本帧刚按下 |
124
+ | `g.key_released("esc")` | 本帧刚松开 |
125
+ | `g.mouse_x, g.mouse_y` / `g.mouse_pos` | 鼠标坐标(游戏内坐标) |
126
+ | `g.mouse_held(1)` / `g.mouse_pressed(1)` | 左键按住 / 刚按下 |
127
+ | `g.on_click = lambda x, y, button: ...` | 点击回调 |
128
+ | `g.touches` | 触屏触摸点列表 |
129
+
130
+ ### 绘制
131
+
132
+ | 写法 | 作用 |
133
+ |---|---|
134
+ | `g.clear("dark")` | 清屏 |
135
+ | `g.rect(x, y, w, h, "red", width=0, radius=8)` | 矩形(width=0 实心) |
136
+ | `g.border(x, y, w, h, "white", width=2)` | 描边矩形 |
137
+ | `g.circle(x, y, r, "orange")` | 圆 |
138
+ | `g.ellipse(x, y, w, h, "cyan")` | 椭圆 |
139
+ | `g.line(x1, y1, x2, y2, "gold", width=2)` | 线段 |
140
+ | `g.polygon([(x,y), ...], "grass")` | 多边形 |
141
+ | `g.arc(x, y, r, 0, 3.14)` | 圆弧 |
142
+ | `g.text("你好", x, y, size=24, color="white", center=True)` | 文字,返回矩形可做命中检测 |
143
+ | `g.image(img, x, y, angle=0, scale=1.0)` | 图片 |
144
+
145
+ 颜色支持 `"red"`、`"#ff0000"`、`(255,0,0)`,另附赠 `dark/gold/orange/cyan/skyblue/grass/brick` 等好看的名字。
146
+
147
+ ### 精灵
148
+
149
+ ```python
150
+ s = pc.sprite("hero.png", 400, 300) # 从图片加载
151
+ s = pc.Sprite.solid("red", 50, 50, 400, 300) # 纯色块
152
+ s = pc.Sprite("walk.png", frames=4, fps=10) # 逐帧动画
153
+
154
+ s.vx, s.vy = 200, -100 # 速度(像素/秒)
155
+ s.move(dt) # 按速度移动
156
+ s.animate(dt) # 播放动画
157
+ s.bounce_in(800, 600) # 撞墙反弹
158
+ s.collides_with(other) # 矩形碰撞
159
+ s.collides_circle(other) # 圆形碰撞
160
+ s.draw(g) # 画出来
161
+ s.kill() # 标记删除(配合 s.alive 过滤)
162
+ ```
163
+
164
+ ### 音频
165
+
166
+ ```python
167
+ pc.play("hit.wav", volume=0.8) # 音效
168
+ pc.music("bgm.mp3") # 循环 BGM
169
+ pc.stop_music() / pc.pause_music() / pc.resume_music()
170
+ ```
171
+
172
+ ### 场景
173
+
174
+ ```python
175
+ class Menu(pc.Scene):
176
+ def draw(self, g):
177
+ g.text("按空格开始", 400, 300, size=36, center=True)
178
+ def update(self, g, dt):
179
+ if g.key_pressed("space"):
180
+ self.switch(Playing())
181
+
182
+ pc.run(scene=Menu)
183
+ ```
184
+
185
+ `self.switch(s)` 换场景、`self.push(s)` 压栈(暂停界面)、`self.pop()` 返回。
186
+
187
+ ### 小工具
188
+
189
+ `pc.clamp` `pc.lerp` `pc.dist` `pc.rand` `pc.randint` `pc.choice` `pc.chance` `pc.Vector`
190
+
191
+ ## 示例
192
+
193
+ ```bash
194
+ python examples/01_hello.py # 一行代码
195
+ python examples/02_bounce.py # 键盘 + 反弹
196
+ python examples/03_catch.py # 完整小游戏
197
+ python examples/04_scene.py # 场景管理
198
+ python examples/05_paint.py # 鼠标画板
199
+ python examples/06_anim.py # 逐帧动画
200
+ python examples/07_window.py # 窗口大小 / 全屏 / 鼠标控制
201
+ ```
202
+
203
+ ## 它是怎么做到"零适配"的
204
+
205
+ 1. **虚拟画布**:所有绘制先画在 800x600 的离屏画布上,再整体等比缩放贴到真实窗口(信箱式留边),所以窗口多大、玩家屏幕多稀奇,你的坐标永远对。
206
+ 2. **高 DPI**:Windows 下自动声明 `per monitor` DPI 感知,笔记本 150% 缩放不再模糊错位。
207
+ 3. **中文字体**:内置 Windows/macOS/Linux 三平台字体候选链,自动挑选第一个可用的。
208
+ 4. **无声降级**:没有音频设备时音效函数静默跳过,游戏照常跑。
209
+
210
+ ## 开发与测试
211
+
212
+ ```bash
213
+ pip install -e . # 可编辑安装
214
+ python tests/test_headless.py # 无头测试(SDL dummy 驱动,无需显示器)
215
+ ```
216
+
217
+ ## 路线图
218
+
219
+ - [ ] 瓦片地图 / 摄像机跟随
220
+ - [ ] 简单物理(重力、平台碰撞)
221
+ - [ ] 打包成 exe 的辅助命令
@@ -0,0 +1,202 @@
1
+ # pycoode
2
+
3
+ **让做游戏像写一行代码一样简单。**
4
+
5
+ `pycoode` 是基于 pygame 的极简 2D 游戏开发包。它替你扛下了所有麻烦事:
6
+ 窗口创建、中文字体、高 DPI、分辨率适配、游戏循环、输入、精灵、音效、场景管理。
7
+ 你只需要写游戏逻辑。
8
+
9
+ ## 特性
10
+
11
+ - **一行起跑** —— `pc.run()` 直接弹窗口;`pc.run(draw=...)` 就能画出东西
12
+ - **零适配问题** —— 游戏按设计分辨率(如 800x600)写坐标,窗口任意拉伸自动信箱缩放、不变形不错位;Windows 高 DPI(150% 缩放)自动适配
13
+ - **中文开箱即用** —— 自动匹配系统中文字体,`g.text("你好")` 不用准备字体文件
14
+ - **输入超简单** —— `g.key_held("space")`、`g.mouse_pressed(1)`,支持方向键/WASD/触屏
15
+ - **精灵系统** —— 移动、旋转、缩放、翻转、矩形/圆形碰撞、逐帧动画,`Sprite.solid("red", 50, 50)` 没有美术素材也能开工
16
+ - **音效一行播放** —— `pc.play("hit.wav")`、`pc.music("bgm.mp3")`,无声环境自动降级不崩溃
17
+ - **场景管理** —— 菜单 / 关卡 / 结算各自一个类,`self.switch(...)` 秒切换
18
+ - **跨平台** —— Windows / macOS / Linux,Python 3.8+
19
+
20
+ ## 安装
21
+
22
+ ```bash
23
+ pip install pygame pycoode
24
+ ```
25
+
26
+ ## 30 秒上手
27
+
28
+ **第 1 行代码:**
29
+
30
+ ```python
31
+ import pycoode as pc
32
+
33
+ pc.run(draw=lambda g: g.text("Hello, pycoode!", 400, 300, size=48,
34
+ color="gold", center=True))
35
+ ```
36
+
37
+ **一个能玩的小游戏(键盘控制 + 碰撞 + 计分):**
38
+
39
+ ```python
40
+ import pycoode as pc
41
+
42
+ player = pc.Sprite.solid("cyan", 48, 48, 400, 520)
43
+ coins, score = [], 0
44
+
45
+ def update(g, dt):
46
+ global score
47
+ dx = int(g.key_held("right")) - int(g.key_held("left"))
48
+ player.x = pc.clamp(player.x + dx * 420 * dt, 24, 776)
49
+ if pc.chance(dt * 3):
50
+ coins.append(pc.Sprite.solid("gold", 22, 22, pc.rand(30, 770), -20))
51
+ for c in coins:
52
+ c.y += 260 * dt
53
+ if player.collides_with(c):
54
+ c.kill(); score += 1
55
+ coins[:] = [c for c in coins if c.alive and c.y < 640]
56
+
57
+ def draw(g):
58
+ g.clear("dark")
59
+ for c in coins: c.draw(g)
60
+ player.draw(g)
61
+ g.text(f"得分 {score}", 16, 14, size=28, color="white")
62
+
63
+ pc.run(update=update, draw=draw, title="接金币")
64
+ ```
65
+
66
+ **内置演示**(安装后直接玩):
67
+
68
+ ```python
69
+ import pycoode
70
+ pycoode.demo()
71
+ ```
72
+
73
+ ## API 速查
74
+
75
+ ### 入口
76
+
77
+ | 写法 | 作用 |
78
+ |---|---|
79
+ | `pc.run()` | 弹出 800x600 窗口,ESC 退出 |
80
+ | `pc.run(update=f, draw=g)` | 带逻辑和绘制 |
81
+ | `pc.run(scene=Menu())` | 用场景管理 |
82
+ | `pc.run(width=960, height=640, title="...", fps=60, background="dark")` | 常用参数 |
83
+ | `pc.run(size="hd")` | 预设窗口大小:`small/md/large/square/hd/fullhd`,也可 `size=(1280,720)` |
84
+ | `pc.run(fit_screen=True)` | 窗口自动收缩到你的屏幕内(小笔记本不怕超出屏幕) |
85
+ | `pc.run(fullscreen=True, show_fps=True)` | 全屏 / 显示 FPS |
86
+ | `pc.run(mouse_visible=False)` | 隐藏鼠标指针 |
87
+ | `pc.run(icon="icon.png")` | 窗口图标 |
88
+
89
+ ### 窗口控制(运行时)
90
+
91
+ | 写法 | 作用 |
92
+ |---|---|
93
+ | `g.toggle_fullscreen()` | 全屏/窗口切换(快捷键 **F11** 已内置) |
94
+ | `g.set_window_size(1024, 768)` | 随时改窗口大小,游戏画面自动缩放适配,逻辑不用动 |
95
+ | `g.screen_size` | 当前真实窗口像素大小,如 `(1280, 720)` |
96
+ | `g.set_mouse_visible(False)` | 随时隐藏/显示鼠标 |
97
+ | `g.width, g.height` | 游戏设计分辨率(画布大小,永远不变) |
98
+
99
+ ### 输入(都接受 "space"/"a"/"up" 等名字)
100
+
101
+ | 写法 | 作用 |
102
+ |---|---|
103
+ | `g.key_held("right")` | 按住中 |
104
+ | `g.key_pressed("space")` | 本帧刚按下 |
105
+ | `g.key_released("esc")` | 本帧刚松开 |
106
+ | `g.mouse_x, g.mouse_y` / `g.mouse_pos` | 鼠标坐标(游戏内坐标) |
107
+ | `g.mouse_held(1)` / `g.mouse_pressed(1)` | 左键按住 / 刚按下 |
108
+ | `g.on_click = lambda x, y, button: ...` | 点击回调 |
109
+ | `g.touches` | 触屏触摸点列表 |
110
+
111
+ ### 绘制
112
+
113
+ | 写法 | 作用 |
114
+ |---|---|
115
+ | `g.clear("dark")` | 清屏 |
116
+ | `g.rect(x, y, w, h, "red", width=0, radius=8)` | 矩形(width=0 实心) |
117
+ | `g.border(x, y, w, h, "white", width=2)` | 描边矩形 |
118
+ | `g.circle(x, y, r, "orange")` | 圆 |
119
+ | `g.ellipse(x, y, w, h, "cyan")` | 椭圆 |
120
+ | `g.line(x1, y1, x2, y2, "gold", width=2)` | 线段 |
121
+ | `g.polygon([(x,y), ...], "grass")` | 多边形 |
122
+ | `g.arc(x, y, r, 0, 3.14)` | 圆弧 |
123
+ | `g.text("你好", x, y, size=24, color="white", center=True)` | 文字,返回矩形可做命中检测 |
124
+ | `g.image(img, x, y, angle=0, scale=1.0)` | 图片 |
125
+
126
+ 颜色支持 `"red"`、`"#ff0000"`、`(255,0,0)`,另附赠 `dark/gold/orange/cyan/skyblue/grass/brick` 等好看的名字。
127
+
128
+ ### 精灵
129
+
130
+ ```python
131
+ s = pc.sprite("hero.png", 400, 300) # 从图片加载
132
+ s = pc.Sprite.solid("red", 50, 50, 400, 300) # 纯色块
133
+ s = pc.Sprite("walk.png", frames=4, fps=10) # 逐帧动画
134
+
135
+ s.vx, s.vy = 200, -100 # 速度(像素/秒)
136
+ s.move(dt) # 按速度移动
137
+ s.animate(dt) # 播放动画
138
+ s.bounce_in(800, 600) # 撞墙反弹
139
+ s.collides_with(other) # 矩形碰撞
140
+ s.collides_circle(other) # 圆形碰撞
141
+ s.draw(g) # 画出来
142
+ s.kill() # 标记删除(配合 s.alive 过滤)
143
+ ```
144
+
145
+ ### 音频
146
+
147
+ ```python
148
+ pc.play("hit.wav", volume=0.8) # 音效
149
+ pc.music("bgm.mp3") # 循环 BGM
150
+ pc.stop_music() / pc.pause_music() / pc.resume_music()
151
+ ```
152
+
153
+ ### 场景
154
+
155
+ ```python
156
+ class Menu(pc.Scene):
157
+ def draw(self, g):
158
+ g.text("按空格开始", 400, 300, size=36, center=True)
159
+ def update(self, g, dt):
160
+ if g.key_pressed("space"):
161
+ self.switch(Playing())
162
+
163
+ pc.run(scene=Menu)
164
+ ```
165
+
166
+ `self.switch(s)` 换场景、`self.push(s)` 压栈(暂停界面)、`self.pop()` 返回。
167
+
168
+ ### 小工具
169
+
170
+ `pc.clamp` `pc.lerp` `pc.dist` `pc.rand` `pc.randint` `pc.choice` `pc.chance` `pc.Vector`
171
+
172
+ ## 示例
173
+
174
+ ```bash
175
+ python examples/01_hello.py # 一行代码
176
+ python examples/02_bounce.py # 键盘 + 反弹
177
+ python examples/03_catch.py # 完整小游戏
178
+ python examples/04_scene.py # 场景管理
179
+ python examples/05_paint.py # 鼠标画板
180
+ python examples/06_anim.py # 逐帧动画
181
+ python examples/07_window.py # 窗口大小 / 全屏 / 鼠标控制
182
+ ```
183
+
184
+ ## 它是怎么做到"零适配"的
185
+
186
+ 1. **虚拟画布**:所有绘制先画在 800x600 的离屏画布上,再整体等比缩放贴到真实窗口(信箱式留边),所以窗口多大、玩家屏幕多稀奇,你的坐标永远对。
187
+ 2. **高 DPI**:Windows 下自动声明 `per monitor` DPI 感知,笔记本 150% 缩放不再模糊错位。
188
+ 3. **中文字体**:内置 Windows/macOS/Linux 三平台字体候选链,自动挑选第一个可用的。
189
+ 4. **无声降级**:没有音频设备时音效函数静默跳过,游戏照常跑。
190
+
191
+ ## 开发与测试
192
+
193
+ ```bash
194
+ pip install -e . # 可编辑安装
195
+ python tests/test_headless.py # 无头测试(SDL dummy 驱动,无需显示器)
196
+ ```
197
+
198
+ ## 路线图
199
+
200
+ - [ ] 瓦片地图 / 摄像机跟随
201
+ - [ ] 简单物理(重力、平台碰撞)
202
+ - [ ] 打包成 exe 的辅助命令
@@ -0,0 +1,37 @@
1
+ """pycoode —— 让做游戏像写一行代码一样简单
2
+
3
+ 基于 pygame 封装: 自动处理窗口创建、中文字体、高 DPI、
4
+ 分辨率适配、游戏循环、输入、精灵、音效和场景。
5
+ """
6
+
7
+ from .core import Game, run, keycode
8
+ from .sprites import Sprite, load_image
9
+ from .scene import Scene
10
+ from .audio import (
11
+ play, music, stop_music, pause_music, resume_music,
12
+ set_music_volume, is_music_playing,
13
+ )
14
+ from .utils import (
15
+ Vector, to_color, clamp, lerp, dist, angle,
16
+ rand, randint, choice, chance,
17
+ )
18
+ from .demo import demo
19
+
20
+ __version__ = "1.0.0"
21
+
22
+
23
+ def sprite(path, x=0, y=0, **kw):
24
+ """加载精灵: pc.sprite("hero.png", 400, 300)"""
25
+ return Sprite.load(path, x, y, **kw)
26
+
27
+
28
+ __all__ = [
29
+ "Game", "run", "demo", "keycode",
30
+ "Sprite", "sprite", "load_image",
31
+ "Scene",
32
+ "play", "music", "stop_music", "pause_music", "resume_music",
33
+ "set_music_volume", "is_music_playing",
34
+ "Vector", "to_color", "clamp", "lerp", "dist", "angle",
35
+ "rand", "randint", "choice", "chance",
36
+ "__version__",
37
+ ]
@@ -0,0 +1,69 @@
1
+ """pycoode.audio —— 音效与背景音乐,一行播放
2
+
3
+ 没有音频设备时所有函数静默降级,不会让游戏崩掉。
4
+ """
5
+
6
+ import pygame
7
+
8
+ _sound_cache = {}
9
+ _mixer_ok = True
10
+
11
+
12
+ def _ensure_mixer():
13
+ global _mixer_ok
14
+ if not _mixer_ok:
15
+ return False
16
+ try:
17
+ if not pygame.mixer.get_init():
18
+ pygame.mixer.init()
19
+ return True
20
+ except Exception:
21
+ _mixer_ok = False
22
+ return False
23
+
24
+
25
+ def play(path, volume=1.0):
26
+ """播放音效(可重复调用,自动缓存)"""
27
+ if not _ensure_mixer():
28
+ return None
29
+ key = str(path)
30
+ if key not in _sound_cache:
31
+ _sound_cache[key] = pygame.mixer.Sound(key)
32
+ s = _sound_cache[key]
33
+ s.set_volume(max(0.0, min(1.0, volume)))
34
+ s.play()
35
+ return s
36
+
37
+
38
+ def music(path, loop=True, volume=0.6, fade_ms=0):
39
+ """播放背景音乐(默认循环)"""
40
+ if not _ensure_mixer():
41
+ return
42
+ pygame.mixer.music.load(str(path))
43
+ pygame.mixer.music.set_volume(max(0.0, min(1.0, volume)))
44
+ pygame.mixer.music.play(-1 if loop else 0, fade_ms=fade_ms)
45
+
46
+
47
+ def stop_music(fade_ms=0):
48
+ if not _ensure_mixer():
49
+ return
50
+ pygame.mixer.music.fadeout(fade_ms) if fade_ms else pygame.mixer.music.stop()
51
+
52
+
53
+ def pause_music():
54
+ if _ensure_mixer():
55
+ pygame.mixer.music.pause()
56
+
57
+
58
+ def resume_music():
59
+ if _ensure_mixer():
60
+ pygame.mixer.music.unpause()
61
+
62
+
63
+ def set_music_volume(v):
64
+ if _ensure_mixer():
65
+ pygame.mixer.music.set_volume(max(0.0, min(1.0, v)))
66
+
67
+
68
+ def is_music_playing():
69
+ return _ensure_mixer() and pygame.mixer.music.get_busy()