音效设计指南
这不是一个单独的配方,而是一份技巧合集——教你用 Yumina 的音频系统打造完整的听觉体验:跟随场景切换的 BGM、关键词触发的音效、循环的环境音、丝滑的交叉淡入淡出,以及从自定义 UI 和 AI 叙述中控制音乐的各种方法。
概览
Yumina 的音频系统有多个入口,可以从不同层面控制声音:
| 控制方式 | 在哪设置 | 特点 |
|---|---|---|
| 播放列表自动播放 | 音频 标签页 | 最简单,进入世界就有背景音乐 |
| 条件 BGM | 音频 标签页 | 变量/关键词/回合数满足条件时自动切歌,不需要写行为 |
| 行为 + 播放音乐动作 | 行为 标签页 | 场景切换时交叉淡入淡出,配合修改变量和开关条目一起用 |
| AI 音频指令 | AI 在回复里写 [audio: ...] | AI 自己决定什么时候播什么,最灵活也最不可控 |
| 消息渲染器 API | 消息渲染器 标签页 | 从自定义按钮触发,适合做点歌机等交互 UI |
本指南按 7 个模式逐一讲解,你可以按需取用,也可以组合使用。
模式 1:基础 BGM 设置
你要做的
让玩家一进入你的世界就听到背景音乐,循环播放,不需要任何额外操作。
一步步来
第 1 步:上传音频轨道
编辑器 → 音频 标签页 → 点击「添加音轨」
| 字段 | 填什么 | 为什么这样填 |
|---|---|---|
| 显示名称 | 主题曲 | 给你自己看的 |
| ID | main_theme | 后面所有引用都用这个 ID |
| 类型 | BGM | 背景音乐 |
| 音频文件 | 上传你的 .mp3 或 .ogg 文件 | 支持常见音频格式 |
| 循环 | 开启 | BGM 通常需要循环 |
| 音量 | 0.7 | 不要太大声,留出空间给音效和环境音 |
| 淡入 | 2 秒 | 进入时渐渐响起,不突兀 |
想多放几首?重复上面的步骤,创建多条音轨。比如
explore_bgm(探索曲)、battle_bgm(战斗曲)、town_bgm(城镇曲)。
第 2 步:设置播放列表
同在 音频 标签页,找到「BGM 播放列表」区域:
| 字段 | 填什么 | 为什么这样填 |
|---|---|---|
| 曲目列表 | 选择 main_theme(如果有多首就全选) | 列表里的曲目会按顺序播放 |
| 播放模式 | loop(循环)或 shuffle(随机) | loop = 按顺序循环;shuffle = 随机打乱 |
| 自动播放 | 开启 | 进入世界就自动放 |
| 等待首条消息 | 关闭(或根据需要开启) | 开启的话,音乐会等到玩家发出第一条消息后才开始 |
| 间隔秒数 | 0(或 2) | 两首曲子之间的停顿,0 = 无缝衔接 |
效果
玩家进入世界 → 音乐自动响起(带 2 秒淡入)→ 一首放完自动放下一首 → 列表放完从头再来。
只有一首 BGM?
如果你只有一首曲,直接把音轨的 loop 打开,播放列表里只放它一首就行。甚至可以不设播放列表,直接用条件 BGM 或 AI 指令来控制。
模式 2:场景切换时 BGM 交叉淡入淡出
你要做的
玩家从「村庄」移动到「地牢」时,村庄的悠扬音乐渐渐变小,地牢的阴森音乐渐渐变大——两首曲子有一小段时间同时播放,过渡丝滑无缝。
原理
玩家点击「前往地牢」按钮
→ 行为触发:修改变量 location = "dungeon"
→ 同一行为里的播放音乐动作:crossfade 到 dungeon_bgm
→ 旧曲目淡出 + 新曲目淡入,过渡时长 2 秒一步步来
第 1 步:准备音轨
在 音频 标签页创建两条(或更多)BGM 音轨:
village_bgm——村庄音乐,类型 BGM,循环开启dungeon_bgm——地牢音乐,类型 BGM,循环开启
播放列表里放 village_bgm 作为默认曲目,自动播放开启。
第 2 步:创建变量
编辑器 → 变量 标签页 → 添加变量
| 字段 | 填什么 |
|---|---|
| 显示名称 | 当前地点 |
| ID | location |
| 类型 | 字符串 |
| 默认值 | village |
第 3 步:创建行为
编辑器 → 行为 标签页 → 添加行为
行为名称: 前往地牢
触发条件: 动作 → 动作 ID 填 go-dungeon
执行动作(按顺序):
| 序号 | 动作类型 | 设置 | 作用 |
|---|---|---|---|
| 1 | 修改变量 | location 设为 dungeon | 记录玩家去了地牢 |
| 2 | 播放音乐 | 音轨 dungeon_bgm,操作:crossfade,渐变时长 2 秒 | 丝滑切歌 |
| 3 | 启用知识条目 | 地牢氛围 | 打开地牢的世界观 |
| 4 | 禁用知识条目 | 村庄氛围 | 关掉村庄的世界观 |
同样创建「返回村庄」行为,动作 ID go-village,执行反向操作(crossfade 到 village_bgm,开关条目反过来)。
第 4 步:在消息渲染器里触发
在 消息渲染器 的 TSX 代码中,按钮点击时调用 executeAction:
<button onClick={() => api.executeAction("go-dungeon")}>
前往地牢
</button>行为会依次执行所有动作——改变量、切歌、开关条目,一键搞定。
什么是 crossfade? 交叉淡入淡出——旧曲目渐渐变小声的同时,新曲目渐渐变大声。两首曲子有一小段时间同时播放,听起来像电影场景切换,不会突然断掉。渐变时长建议 2-3 秒。
模式 3:关键词触发音效
你要做的
AI 写到"爆炸"时自动播放爆炸音效。玩家说"开门"时播放门打开的嘎吱声。不需要写行为,直接在 音频 标签页的条件 BGM 里就能配。
原理
条件 BGM 有一个触发方式叫 ai-keyword(AI 关键词)和 keyword(玩家关键词)。引擎会扫描每条消息的文字,匹配到关键词就播放对应的音轨。虽然功能名字叫"条件 BGM",但它可以指向任何类型的音轨——包括 SFX。
一步步来
第 1 步:创建 SFX 音轨
在 音频 标签页创建音效轨道:
爆炸音效:
| 字段 | 填什么 |
|---|---|
| 显示名称 | 爆炸 |
| ID | explosion_sfx |
| 类型 | SFX |
| 循环 | 关闭(音效通常只播一次) |
| 音量 | 0.9 |
开门音效:
| 字段 | 填什么 |
|---|---|
| 显示名称 | 开门声 |
| ID | door_open_sfx |
| 类型 | SFX |
| 循环 | 关闭 |
| 音量 | 0.8 |
第 2 步:创建条件 BGM 规则
同在 音频 标签页,找到「条件 BGM」区域 → 点击「添加规则」
规则 1:AI 说"爆炸"时播放音效
| 字段 | 填什么 | 为什么这样填 |
|---|---|---|
| 名称 | AI 爆炸音效 | 给你自己看的 |
| 触发方式 | AI 关键词 (ai-keyword) | 当 AI 的回复里出现指定关键词时触发 |
| 关键词 | 爆炸, 炸裂, 爆破 | 可以填多个近义词,命中任一个就触发 |
| 目标音轨 | explosion_sfx | 播放爆炸音效 |
| 停止当前 BGM | 关闭 | 音效是叠加在 BGM 上面的,不要停 BGM |
规则 2:玩家说"开门"时播放音效
| 字段 | 填什么 | 为什么这样填 |
|---|---|---|
| 名称 | 玩家开门音效 | 给你自己看的 |
| 触发方式 | 玩家关键词 (keyword) | 当玩家发送的消息里出现指定关键词时触发 |
| 关键词 | 开门, 推门, 打开门 | 多个近义词 |
| 目标音轨 | door_open_sfx | 播放开门音效 |
| 停止当前 BGM | 关闭 | 同上 |
效果
AI 写道:「轰——!远处传来一声惊天动地的爆炸,火光照亮了整片天空。」
→ 引擎扫描到「爆炸」→ 自动播放 explosion_sfx
→ 玩家听到爆炸音效,同时 BGM 继续播放
玩家输入:「我走到门前,开门看看。」
→ 引擎扫描到「开门」→ 自动播放 door_open_sfxSFX 和 BGM 的区别
SFX(音效)播一次就停。BGM(背景音乐)会循环或根据播放列表继续。当条件 BGM 规则指向一个 SFX 类型的音轨时,它只会播一次,不会替换正在播的背景音乐。但如果 stopPreviousBGM 设成了 true,它会先停掉当前 BGM 再播这个音轨——SFX 通常不需要这么做。
模式 4:条件 BGM——变量驱动自动切歌
你要做的
不用写行为,直接在 音频 标签页里配一条规则:当 hp 降到 20 以下时,自动切换到紧张的危机音乐;hp 回到 20 以上后,自动切回默认曲目。
原理
条件 BGM 的 variable 触发方式会在每次变量变化后自动检查。条件满足 → 切到目标曲目;条件不再满足 → 根据 fallback 设置回退(回到播放列表默认曲目,或回到之前那首)。
一步步来
第 1 步:准备音轨
确保 音频 标签页里有:
explore_bgm——默认探索音乐(在播放列表里)crisis_bgm——危机音乐(只在条件触发时播放,不需要放进播放列表)
第 2 步:创建条件 BGM 规则
音频 标签页 → 条件 BGM → 添加规则
| 字段 | 填什么 | 为什么这样填 |
|---|---|---|
| 名称 | 低血量危机音乐 | 给你自己看的 |
| 触发方式 | 变量 (variable) | 根据变量值来决定 |
| 条件 | hp < 20 | 当 hp 小于 20 时触发 |
| 条件逻辑 | 全部满足 (all) | 只有一个条件,all 和 any 效果一样 |
| 目标音轨 | crisis_bgm | 切到危机音乐 |
| 优先级 | 10 | 如果有多条规则同时满足,优先级高的赢 |
| 淡入时长 | 1 秒 | 新曲目渐渐响起 |
| 淡出时长 | 1 秒 | 旧曲目渐渐消失 |
| 停止当前 BGM | 开启 | 停掉探索曲再播危机曲 |
| 回退 | default | 条件不再满足时(hp 回到 20 以上),自动回到播放列表的默认曲目 |
效果
玩家探索中,BGM 是 explore_bgm
→ AI 回复:[hp: -15](hp 从 30 降到 15)
→ 引擎检测到 hp < 20,条件满足
→ explore_bgm 1 秒淡出,crisis_bgm 1 秒淡入
→ 气氛立刻紧张起来
玩家使用治疗药水
→ AI 回复:[hp: +20](hp 从 15 回到 35)
→ 引擎检测到 hp 不再 < 20,条件不满足
→ fallback: "default" → 自动回到 explore_bgm多条件组合
你可以在一条规则里加多个条件。比如:hp < 20 并且 location == "dungeon" → 只有在地牢里低血才播危机音乐。条件逻辑选 all(全部满足)即可。
模式 5:环境音循环
你要做的
在场景背景里持续播放环境音——雨声、风声、酒馆嘈杂声——和 BGM 叠加在一起,增强沉浸感。
原理
Ambient(环境音)是第三种音轨类型。它独立于 BGM 播放——你可以同时播一首 BGM + 一段环境音。环境音通常设为循环、音量较低,作为持续的氛围底色。
一步步来
第 1 步:创建 Ambient 音轨
音频 标签页 → 添加音轨
| 字段 | 填什么 |
|---|---|
| 显示名称 | 雨声 |
| ID | rain_ambient |
| 类型 | Ambient |
| 循环 | 开启 |
| 音量 | 0.3(环境音要比 BGM 小声,作为底色) |
| 淡入 | 3 秒(渐渐出现,不突兀) |
| 淡出 | 3 秒 |
可以多创建几个:wind_ambient(风声)、tavern_ambient(酒馆嘈杂声)、forest_ambient(森林鸟叫虫鸣)。
第 2 步:用条件 BGM 控制环境音
和模式 4 一样,用条件 BGM 规则来控制环境音的播放。
规则:在森林时播放森林环境音
| 字段 | 填什么 |
|---|---|
| 名称 | 森林环境音 |
| 触发方式 | 变量 (variable) |
| 条件 | location == forest |
| 目标音轨 | forest_ambient |
| 停止当前 BGM | 关闭 |
| 回退 | default |
关键:
stopPreviousBGM必须关闭。 环境音是叠加在 BGM 上面的,不应该停掉 BGM。如果开了,切换环境音的时候会把正在播的背景音乐也停掉。
也可以用行为控制
如果你已经有了场景切换的行为(像模式 2 那样),直接在行为的动作列表里加一条「播放音乐」动作,目标是环境音轨即可:
| 序号 | 动作类型 | 设置 | 作用 |
|---|---|---|---|
| 1 | 修改变量 | location 设为 forest | 记录地点 |
| 2 | 播放音乐 | forest_bgm,操作:crossfade,渐变 2 秒 | 切换 BGM |
| 3 | 播放音乐 | forest_ambient,操作:play,淡入 3 秒 | 叠加环境音 |
| 4 | 播放音乐 | tavern_ambient,操作:stop,淡出 3 秒 | 停掉旧环境音 |
这样一条行为同时完成了 BGM 切换 + 环境音更替。
环境音的音量建议
BGM 一般 0.5-0.7,环境音 0.2-0.4,SFX 0.7-1.0。这样三层声音叠在一起不会打架。
模式 6:从自定义组件控制音频
你要做的
在消息渲染器里做一个"点歌机"——几个按钮,点一个就播对应的音乐,点「停止」就停。这是纯 UI 控制,不需要写行为或条件规则。
原理
useYumina() 提供了两个音频 API:
api.playAudio?.(trackId, opts)— 播放指定音轨api.stopAudio?.(trackId?)— 停止指定音轨(不传 ID 则停止全部)
这两个方法可以在消息渲染器的 TSX 代码里直接调用。
一步步来
第 1 步:准备音轨
确保 音频 标签页里已经注册了你想播的音轨(像模式 1 那样创建)。假设你有:
jazz_bgm— 爵士乐rock_bgm— 摇滚classical_bgm— 古典
第 2 步:写消息渲染器代码
编辑器 → 消息渲染器 标签页 → 在渲染器代码里加入点歌机 UI:
export default function Renderer({ content, renderMarkdown, messageIndex }) {
const api = useYumina();
const msgs = api.messages || [];
const isLastMsg = messageIndex === msgs.length - 1;
const tracks = [
{ id: "jazz_bgm", label: "爵士乐", color: "#7c3aed" },
{ id: "rock_bgm", label: "摇滚", color: "#dc2626" },
{ id: "classical_bgm", label: "古典", color: "#0891b2" },
];
return (
<div>
<div
style={{ color: "#e2e8f0", lineHeight: 1.7 }}
dangerouslySetInnerHTML={{ __html: renderMarkdown(content) }}
/>
{isLastMsg && (
<div style={{
marginTop: "12px",
padding: "12px",
background: "rgba(30,41,59,0.5)",
borderRadius: "8px",
border: "1px solid #334155",
}}>
<div style={{ fontSize: "12px", color: "#94a3b8", marginBottom: "8px" }}>
点歌机
</div>
<div style={{ display: "flex", gap: "8px", flexWrap: "wrap" }}>
{tracks.map((t) => (
<button
key={t.id}
onClick={() => api.playAudio?.(t.id, { fadeDuration: 1.5 })}
style={{
padding: "8px 16px",
background: t.color,
border: "none",
borderRadius: "6px",
color: "#fff",
fontSize: "13px",
cursor: "pointer",
}}
>
{t.label}
</button>
))}
<button
onClick={() => api.stopAudio?.()}
style={{
padding: "8px 16px",
background: "#475569",
border: "none",
borderRadius: "6px",
color: "#e2e8f0",
fontSize: "13px",
cursor: "pointer",
}}
>
停止
</button>
</div>
</div>
)}
</div>
);
}代码逐行解释:
api.playAudio?.(t.id, { fadeDuration: 1.5 })— 播放指定音轨,带 1.5 秒淡入。如果当前有其他曲子在播,会自动停掉再播新的api.stopAudio?.()— 不传参数 = 停止所有正在播放的音频isLastMsg— 只在最后一条消息上显示点歌机,避免每条消息都重复
更高级的用法
你可以读取变量来控制 UI 状态。比如用一个变量 now_playing 记录当前曲目 ID,然后在按钮上显示"正在播放"的标记:
const nowPlaying = String(api.variables.now_playing || "");
// 在按钮点击里同时更新变量
onClick={() => {
api.playAudio?.(t.id, { fadeDuration: 1.5 });
api.setVariable("now_playing", t.id);
}}
// 按钮上显示状态
{nowPlaying === t.id ? "♪ " + t.label : t.label}模式 7:AI 驱动的音频控制
你要做的
让 AI 在叙述过程中自然地控制音乐——描写进入酒馆时播放欢快的手风琴曲,描写战斗打响时切到激昂的战斗 BGM,描写角色受伤时播放疼痛音效。
原理
AI 可以在回复中嵌入 [audio: trackId action] 格式的指令。引擎会自动识别并执行这些指令,同时把它们从玩家看到的文字中剥离掉——就像电影剧本里的舞台指示,观众看不到,但幕后工作人员会照着执行。
一步步来
第 1 步:注册所有可能用到的音轨
在 音频 标签页把你想让 AI 控制的音轨全部创建好:
tavern_bgm— 酒馆曲battle_bgm— 战斗曲sword_clash_sfx— 刀剑碰撞音效pain_sfx— 受伤音效rain_ambient— 雨声
第 2 步:在系统提示词里告诉 AI 有哪些音轨
AI 不会自动知道你注册了哪些音轨。你需要在 知识库 标签页创建一个条目,列出可用的音轨和使用规则:
条目名称: 音频指令参考
区域: 预设
内容:
[Audio Control System]
你可以在回复中使用以下音频指令来控制音乐和音效。指令会被自动执行并从玩家可见文字中移除。
可用指令格式:
- [audio: trackId play] — 播放
- [audio: trackId play 2.0] — 播放,带 2 秒淡入
- [audio: trackId stop] — 停止
- [audio: trackId stop 1.5] — 停止,带 1.5 秒淡出
- [audio: trackId crossfade 2.0] — 交叉淡入淡出切换,过渡 2 秒
- [audio: trackId volume 0.5] — 调节音量到 0.5
- [audio: trackId play chain:nextTrackId] — 播完后自动衔接下一首
可用音轨:
- tavern_bgm — 酒馆欢快手风琴曲(适合社交、购物场景)
- battle_bgm — 激昂战斗曲(适合战斗、追逐场景)
- sword_clash_sfx — 刀剑碰撞音效(适合近战动作描写)
- pain_sfx — 受伤音效(适合角色受伤时)
- rain_ambient — 雨声环境音(适合雨天场景)
使用原则:
- 在合适的叙述节点自然地插入音频指令
- 场景转换时用 crossfade 切歌,过渡时长 1.5-2.5 秒
- 音效配合动作描写,放在对应的动作文字旁边
- 不要过度使用——每段回复最多 2-3 条音频指令第 3 步:AI 的回复示例
告诉 AI 这些规则后,它的回复可能长这样:
你推开酒馆的木门,一股温暖的空气扑面而来。[audio: tavern_bgm crossfade 2.0]
酒馆里热闹非凡——角落里有人在弹手风琴,吧台前的矮人正在大声猜拳。你刚找了个座位坐下,一个蒙面人突然拔刀朝你劈来!
[audio: battle_bgm crossfade 0.5] [audio: sword_clash_sfx play]
你本能地翻身躲开,桌子被劈成两半。玩家看到的是干净的叙述文字,同时听到:酒馆曲渐入 → 突然切战斗曲 + 刀剑碰撞音效。
chain 指令的特殊用法
chain 可以让一个音轨播完后自动衔接另一个:
号角声在山谷间回荡,战争即将开始![audio: war_horn_sfx play chain:battle_bgm]war_horn_sfx 这段号角音效播完后,battle_bgm 会自动开始——先放前奏再接主曲,比直接切歌更有仪式感。
AI 可能忘记使用指令
AI 不总是记得插入音频指令,尤其是在长对话中。对于关键场景的 BGM 切换(比如进入战斗区域),建议同时设置条件 BGM 规则(模式 4)作为保底。AI 指令是锦上添花,条件 BGM 是安全网。
综合速查表
音轨类型
| 类型 | 用途 | 通常设置 |
|---|---|---|
| BGM | 背景音乐 | 循环开启,音量 0.5-0.7 |
| SFX | 一次性音效 | 循环关闭,音量 0.7-1.0 |
| Ambient | 环境音循环 | 循环开启,音量 0.2-0.4 |
控制音频的 5 种方法
| 你想做的事 | 用哪种方式 | 在哪里设置 |
|---|---|---|
| 进入世界自动播放 BGM | 播放列表 + 自动播放 | 音频 标签页 → BGM 播放列表 |
| 变量满足条件时自动切歌 | 条件 BGM(variable 触发) | 音频 标签页 → 条件 BGM |
| AI 回复出现关键词时播音效 | 条件 BGM(ai-keyword 触发) | 音频 标签页 → 条件 BGM |
| 玩家消息出现关键词时播音效 | 条件 BGM(keyword 触发) | 音频 标签页 → 条件 BGM |
| 到指定回合数时切歌 | 条件 BGM(turn-count 触发) | 音频 标签页 → 条件 BGM |
| 场景切换时交叉淡入淡出 | 行为 + 播放音乐动作 | 行为 标签页 |
| 按钮点击播放/停止 | 消息渲染器 api.playAudio?.() / api.stopAudio?.() | 消息渲染器 标签页 |
| AI 在叙述中触发 | AI 音频指令 [audio: trackId action] | 知识库 标签页(告诉 AI 规则) |
AI 音频指令速查
| 指令 | 效果 |
|---|---|
[audio: trackId play] | 播放 |
[audio: trackId play 2.0] | 播放,2 秒淡入 |
[audio: trackId stop] | 停止 |
[audio: trackId stop 1.5] | 停止,1.5 秒淡出 |
[audio: trackId crossfade 2.0] | 交叉淡入淡出,过渡 2 秒 |
[audio: trackId volume 0.5] | 调节音量 |
[audio: trackId play chain:nextId] | 播完后自动衔接下一首 |
条件 BGM 触发方式
| 触发方式 | 什么时候触发 | 典型用途 |
|---|---|---|
variable | 变量满足条件时 | hp < 20 播危机曲 |
ai-keyword | AI 回复含关键词时 | AI 写"爆炸"播爆炸音效 |
keyword | 玩家消息含关键词时 | 玩家说"演奏"播音乐 |
turn-count | 到达指定回合时 | 第 10 回合播倒计时曲 |
session-start | 会话开始时 | 固定的开场曲 |
行为 play-audio 动作参数
| 参数 | 说明 |
|---|---|
音轨 ID (trackId) | 对应音频标签页里注册的音轨 ID |
操作 (action) | play(播放)、stop(停止)、crossfade(渐变切换)、volume(调音量) |
音量 (volume) | 0-1,可选 |
渐变时长 (fadeDuration) | 秒,可选,crossfade 时建议 1.5-3 秒 |
消息渲染器音频 API
| 方法 | 说明 |
|---|---|
api.playAudio?.(trackId, opts) | 播放音轨。opts 可以包含 fadeDuration 等 |
api.stopAudio?.(trackId?) | 停止音轨。不传 ID 则停止全部 |
常见问题
| 现象 | 可能的原因 | 解决方法 |
|---|---|---|
| 听不到声音 | 浏览器禁止自动播放 | 现代浏览器要求用户先和页面有交互(点击、打字)才允许播放音频。让玩家先发一条消息,或在播放列表里把「等待首条消息」打开 |
| BGM 切换时有断裂感 | 没用 crossfade | 确认行为的「播放音乐」操作选的是 crossfade,渐变时长至少 1.5 秒 |
| 音效和 BGM 互相打断 | stopPreviousBGM 设成了 true | SFX 类型的条件 BGM 规则要把「停止当前 BGM」关掉 |
| AI 不使用音频指令 | 知识条目里没告诉 AI | 创建一个预设条目,列出所有可用的音轨 ID 和指令格式(见模式 7) |
| 环境音太吵 | 音量太高 | 环境音建议 0.2-0.4,和 BGM 的 0.5-0.7 拉开层次 |
| 条件 BGM 没触发 | 变量值类型不匹配 | 确认条件里的值类型和变量类型一致(比如数字变量要用数字比较,不要写成字符串) |
| 多条规则冲突 | 优先级相同 | 给不同的条件 BGM 规则设不同的优先级,数字越大越优先 |
这是实战配方 #14:音效设计指南
音频系统的设计哲学是:简单的事情一步到位(播放列表 + 自动播放),复杂的事情分层解锁(条件 BGM → 行为控制 → AI 指令 → 自定义 API)。你不需要一次学完所有模式——从模式 1 开始,等需要更多控制时再往后看。
