声音
用 Sound 播放音效、背景音乐与语音片段,并用 Control.doAsync 让播放与剧情并行推进
使用 Sound 播放音效、背景音乐和语音。静态构造方法会为声音设置正确类型
import { Sound } from "narraleaf-react";
const door = Sound.sound({
src: "/audio/door.ogg",
volume: 0.8,
});
const theme = Sound.bgm({
src: "/audio/theme.ogg",
volume: 0.5,
loop: true,
});音效
play() 返回一个动作。默认情况下,剧情会等到音频播放结束
scene.action([
door.play(),
alice.say("有人来了。"),
]);如果剧情需要在声音播放时继续执行,可把声音放到异步控制栈
import { Control } from "narraleaf-react";
scene.action([
Control.doAsync([door.play()]),
alice.say("门在你身后关上了。"),
]);旧版的 sync 配置已经移除。非阻塞音频请使用 Control.doAsync() 或 Control.allAsync()
背景音乐
可以在场景配置中指定 BGM,也可以在剧情中更换。淡入淡出时间的单位是毫秒
const room = new Scene("房间", {
backgroundMusic: theme,
backgroundMusicFade: 800,
});
room.action([
room.setBackgroundMusic(Sound.bgm("/audio/night.ogg"), 800),
]);传入 null 可以停止当前 BGM
room.setBackgroundMusic(null, 500);前奏与循环区间
seek 是音频的入点,endTime 是出点。配合 loop,这一对就构成了循环区间,而 loopStart 指定每一遍回到哪里——
带前奏的背景音乐正是这样先完整播一遍开头,然后只重复主体
const theme = Sound.bgm({
src: "/audio/theme.ogg",
loop: true,
seek: 0, // 第一遍从头开始
loopStart: 12, // 之后每一遍都回到这里,跳过前奏
endTime: 90,
});循环是采样级精确的——接缝处没有空隙,长时间播放也不会漂移。参见 ISoundUserConfig
要移动正在播放的音频的播放头,把 seek() 当作动作使用:
room.action([
theme.seek(12), // 跳过前奏
]);音量与总线
每段音频都在某条音频总线上播放,由它的 type 决定。游戏无需声明就拥有 bgm、sound 和 voice,
也可以再声明更多——比如为每个角色一条总线——从而提供固定三条总线表达不出的玩家控制
参见音频总线
播放控制
Sound 动作可以调整播放状态和参数
scene.action([
door.setVolume(0.3, 300),
door.setRate(1.2),
door.pause(200),
door.resume(200),
door.mute(),
door.unmute(),
door.stop(300),
]);在 React UI 中需要立即播放声音时,使用 liveGame.playSound(),不用创建剧情动作
const liveGame = useLiveGame();
<button onClick={() => liveGame.playSound("/audio/click.ogg")}>播放</button>