使用 Pyxel 入门 2D 游戏(第12部分):播放音效
发布: (2026年1月15日 GMT+8 23:00)
4 min read
原文: Dev.to
Source: Dev.to
注册声音
首先,在 Game 类的构造函数中注册一个声音。
pyxel.sound() 的参数指定 声音 ID。
- 声音 ID – 该数字稍后在播放声音时使用。
接下来,将以下数据传递给 set() 方法:
| 参数 | 描述 |
|---|---|
notes (score) | 指定音高 |
tones | 波形类型(例如 p = 脉冲波) |
volumes | 音量 |
effects | 声音效果(例如 f = 渐弱) |
speed | 播放速度(数值越低播放越快) |
# main.py
pyxel.sound(0).set(
"c4g3",
tones="p",
volumes="76",
effects="f",
speed=20
)
播放声音
使用 pyxel.play() 时,最多可以同时播放四个声音。
- 第一个参数指定 通道号(0–3)。
如果使用相同的通道,新声音会覆盖之前的声音。 - 第二个参数指定 声音 ID。
# main.py
pyxel.play(0, 0)
完整代码
下面是实现本文中介绍的功能的完整代码。
(sprite.py 文件与前一章节相同。)
# main.py
import pyxel
import math
import random
import sprite
W, H = 160, 120
SHIP_SPD = 1.4
ASTEROID_INTERVAL = 20
ASTEROID_LIMIT = 30
ASTEROID_SPD_MIN = 1.0
ASTEROID_SPD_MAX = 2.0
ASTEROID_DEG_MIN = 30
ASTEROID_DEG_MAX = 150
BULLET_SPD = 3
# Game
class Game:
def __init__(self):
"""Constructor"""
# Game over flag
self.game_over_flg = False
# Initialize score
self.score = 0
# Initialize player
self.ship = sprite.ShipSprite(W / 2, H - 40)
deg = 0 if random.random() < 0.5 else 180
self.ship.move(SHIP_SPD, deg)
# Asteroids
self.asteroid_time = 0
self.asteroids = []
# Bullets
self.bullets = []
# Initialize Pyxel
pyxel.init(W, H, title="Hello, Pyxel!!")
pyxel.load("shooter.pyxres")
# Sound (shot)
pyxel.sound(0).set(
"c4g3",
tones="p",
volumes="76",
effects="f",
speed=20
)
# Sound (hit)
pyxel.sound(1).set(
"e4d4c4",
tones="p",
volumes="76",
effects="n",
speed=20
)
pyxel.run(self.update, self.draw)
def update(self):
"""Update process"""
# Game over
if self.game_over_flg:
return
# Update player
self.ship.update()
self.control_ship()
self.overlap_spr(self.ship)
self.check_interval() # Add asteroids
# Update asteroids
for asteroid in self.asteroids:
asteroid.update()
self.overlap_spr(asteroid)
# Collision check (asteroid × player)
if asteroid.intersects(self.ship):
self.game_over_flg = True
# Update bullets (reverse order)
for bullet in self.bullets[::-1]:
bullet.update()
# Remove if outside screen
if bullet.y < 0:
self.bullets.remove(bullet)
continue
# Collision check (bullet × asteroid)
for asteroid in self.asteroids[::-1]:
if asteroid.intersects(bullet):
self.score += 1
self.bullets.remove(bullet)
self.asteroids.remove(asteroid)
# Sound (hit)
pyxel.play(1, 1)
return
def draw(self):
"""Draw process"""
pyxel.cls(0)
# Game over
if self.game_over_flg:
msg = "GAME OVER"
pyxel.text(W / 2 - len(msg) * 2, H / 2, msg, 13)
# Draw score
pyxel.text(10, 10, f"SCORE:{self.score:04}", 12)
# Draw player
self.ship.draw()
# Draw asteroids
for asteroid in self.asteroids:
asteroid.draw()
# Draw bullets
for bullet in self.bullets:
bullet.draw()
def control_ship(self):
"""Player action"""
if pyxel.btnp(pyxel.KEY_SPACE):
self.ship.flip_x()
# Fire bullet
bullet = sprite.BulletSprite(self.ship.x, self.ship.y)
bullet.move(BULLET_SPD, 270)
self.bullets.append(bullet)
# Sound (shot)
pyxel.play(0, 0)
def overlap_spr(self, spr):
"""Wrap sprite around the screen"""
if spr.x < -spr.w:
spr.x = W
return
if W < spr.x:
spr.x = -spr.w
return
if spr.y < -spr.h:
spr.y = H
return
if H < spr.y:
spr.y = -spr.h
return
def check_interval(self):
# Asteroid spawn interval
self.asteroid_time += 1
if self.asteroid_time < ASTEROID_INTERVAL:
retu```
```python
rn
self.asteroid_time = 0
# Limit number of asteroids
if ASTEROID_LIMIT < len(self.asteroids):
return
# Add asteroid
x = random.random() * W
y = 0
spd = random.uniform(ASTEROID_SPD_MIN, ASTEROID_SPD_MAX)
deg = random.uniform(ASTEROID_DEG_MIN, ASTEROID_DEG_MAX)
asteroid = sprite.AsteroidSprite(x, y)
asteroid.move(spd, deg)
self.asteroids.append(asteroid)
# Run the game
Game()
全屏控制
- 进入全屏模式
- 退出全屏模式
结束语
感谢您阅读至此。
我希望本系列能成为您自己游戏开发之旅的起点。
如果您喜欢它,点个 👍 将意义重大!
