Skip to content

音频 ​

音效用 sfx(),音乐用 music(),和贴图一样在场景的 static assets 里声明。格式统一用 mp3。

ts
import { AudioStreamPlayer, music, Scene, sfx } from 'sapling2d'

export class Stage extends Scene {
  // 音效预解码(可叠加),音乐流式播放;格式统一用 mp3
  static override assets = { pop: sfx('pop.mp3'), bgm: music('bgm.mp3') }

  override ready() {
    this.add(new AudioStreamPlayer({ stream: Stage.assets.bgm, loop: true, volume: 0.5, autoplay: true }))
  }

  pop() {
    this.tree.audio.play(Stage.assets.pop) // 一次性音效
  }

  hit() {
    // 一帧里可能命中几十次:同一个音效最多同时播 3 个,多的直接不播
    this.tree.audio.play(Stage.assets.pop, { maxVoices: 3, volume: 0.6 })
  }

  toggleMusic() {
    const audio = this.tree.audio
    audio.setBusMute('Music', !audio.isBusMuted('Music')) // 总线:Master / Music / SFX
  }
}
// 浏览器在第一次触摸 / 点击 / 按键时自动解锁声音;切到后台自动挂起

播放 ​

  • 一次性音效:this.tree.audio.play(stream, { volume, loop, bus, maxVoices })。
  • 背景音乐这类需要控制的声音:AudioStreamPlayer 节点,属性 stream、volume、loop、bus、autoplay,方法 play() / stop(),信号 finished。
  • maxVoices 限制同一个声音同时播放的数量,超过时这次不播。命中、爆炸这类一帧可能触发几十次的音效都应该设。
  • 音效预解码,可以叠加播放;音乐流式播放。

总线与音量 ​

  • 三条总线:Master、Music、SFX。setBusMute / isBusMuted 做静音开关。
  • 音量是 0–1,不是 dB。

平台行为 ​

  • 浏览器在第一次触摸、点击或按键时自动解锁声音;切到后台时自动挂起。
  • tree.paused 不会暂停声音。

测试 ​

无头模式不发声,只记录:g.audio.log 是播放记录,g.audio.playing 是正在播放的声音,g.audio.finishAll() 模拟全部播放结束。

ts
const g = await createTestGame({ main: Stage })
g.scene.pop()
g.scene.toggleMusic()
// 无头模式不发声,只记录:g.audio.log / g.audio.playing;g.audio.finishAll() 模拟播放结束
expect(g.audio.log.map((s) => `${s.kind}:${s.path}:${s.volume}`)).toEqual(['music:bgm.mp3:0', 'sfx:pop.mp3:1'])
for (let i = 0; i < 10; i++) g.scene.hit()
expect(g.audio.playing.filter((s) => s.path === 'pop.mp3').length).toBe(3) // 先前的 pop 也算在内

MIT 许可证