系统插槽是引擎预定义的语义 UI 入口。调用方只说「打开设置」或「打开存档」,项目绑定决定最终使用哪一份界面。
这种间接绑定让创作者以后可以替换整套游戏壳,而不必修改剧本和每个按钮。
九个系统插槽
| 插槽 | 常量 | 说明 | 必需 |
|---|
| 标题画面 | INTERNAL_SYSTEM_SLOT.Title | 游戏启动和返回标题时打开 | 是 |
| 对话工具栏 | INTERNAL_SYSTEM_SLOT.Toolbar | 对话期间自动显示的操作工具栏 | 是 |
| 存档界面 | INTERNAL_SYSTEM_SLOT.Save | 以保存模式显示槽位 | 是 |
| 读档界面 | INTERNAL_SYSTEM_SLOT.Load | 以读取模式显示槽位 | 是 |
| 设置界面 | INTERNAL_SYSTEM_SLOT.Settings | 玩家运行时设置 | 否 |
| 历史记录 | INTERNAL_SYSTEM_SLOT.History | 对话回顾和语音重放 | 否 |
| 鉴赏画面 | INTERNAL_SYSTEM_SLOT.Gallery | CG、音乐和剧情片段鉴赏 | 否 |
| 玩家输入 | INTERNAL_SYSTEM_SLOT.Input | 收集并校验玩家输入 | 是 |
| 选项界面 | INTERNAL_SYSTEM_SLOT.Choice | 显示剧情分支选项并返回原选项序号 | 是 |
默认游戏壳提供全部九个插槽。标题、对话工具栏、存档、读档、玩家输入和选项界面的绑定失效时,引擎会回退到内置实现。
对话工具栏由默认游戏壳的自治控制器跟随对话状态打开和关闭。把工具栏插槽改绑到其他界面后,这套显隐时机保持不变,只替换实际显示的界面。
绑定可视化界面
可视化界面不需要程序声明。创建界面后,进入 个性化 → 项目设置 → 游戏系统,在目标插槽中选择它即可。
任何启用扩展中的可视化界面都可以作为候选。系统或市场界面只读,需要修改时先创建项目副本,或复制到本地扩展。
选项界面需要包含「选项列表」智能组件,才能接收分支内容并返回选择结果。玩家输入界面需要使用输入对话框能力处理确认、取消和校验。可以从个性化直接打开默认实现进行修改。
界面里的按钮要打开另一个系统位置时,配置「打开存档」「打开设置」等系统动作。不要写死具体界面,这样按钮会跟随绑定变化。
声明程序 UI 支持
React 程序 UI 需要在 @extension 装饰器中声明 supportsSlot:
import { Extension, extension, INTERNAL_SYSTEM_SLOT } from "@avg-studio/sdk";
@extension({
id: "title-screen",
label: "自定义标题画面",
supportsSlot: INTERNAL_SYSTEM_SLOT.Title,
})
export class MyTitleScreen extends Extension {
render() {
return { component: TitleScreenComponent, props: {} };
}
}
同一个模块可以支持多个插槽:
@extension({
id: "save-screen",
label: "存读档界面",
supportsSlot: [
INTERNAL_SYSTEM_SLOT.Save,
INTERNAL_SYSTEM_SLOT.Load,
],
})
export class MySaveLoadScreen extends Extension {
// 根据打开时的 payload 区分保存和读取模式
}
声明后,模块才会出现在对应插槽的程序 UI 候选中。
从程序触发插槽
// 打开当前绑定的存档界面
await ctx.system.invoke(INTERNAL_SYSTEM_SLOT.Save);
// 传递给目标 UI 的 payload
await ctx.system.invoke(
INTERNAL_SYSTEM_SLOT.Save,
{ mode: "save" },
{
modal: true,
containerOptions: {
size: "(100%, 100%)",
position: "(0, 0)",
},
},
);
const binding = ctx.system.getBinding(INTERNAL_SYSTEM_SLOT.Save);
const slots = ctx.system.listSlots();
// 常驻槽位可以由控制器主动收起
await ctx.system.close(INTERNAL_SYSTEM_SLOT.Toolbar);
invoke 的第三个参数可以设置 modal,以及容器的 size、position 和 interactable。
选项界面的 payload
剧情分支会自动调用 INTERNAL_SYSTEM_SLOT.Choice,并传入:
branchId:当前分支 Block 标识;
choices:过滤后的可见选项,包括原始序号、文字和是否可用;
onSelect(originalIndex):界面确认选择后必须调用的回调。
自定义程序 UI 应只提交可用选项的 originalIndex,然后关闭自身。界面未选择就关闭或调用失败时,引擎会回退到内置选项界面,避免剧情中断。
玩家输入和剧情选项通常由引擎自动调用。普通扩展界面不应在缺少对应 payload 时直接打开这两个插槽。
在剧本中使用
显示 UI选择器的「系统插槽」分组会列出常规可打开入口。保存后使用 slot:internal.system.* 语义引用;项目之后改绑,已有剧本会自动跟随。玩家输入和剧情选项应由对应运行时流程调用,不建议作为普通显示 UI 使用。
内置动作(输入)
系统插槽是「系统 UI 位置」,内置动作是「玩家输入对应的语义」。两者是独立概念。
引擎定义了以下标准动作:
| 动作 | 常量 | 默认按键 | 含义 |
|---|
| 推进对话 | INTERNAL_ACTION.Advance | 鼠标点击 / 空格 / Enter / 滚轮 | 推进到下一句 |
| 跳过 | INTERNAL_ACTION.Skip | Ctrl | 快进到段尾 |
| 自动播放 | INTERNAL_ACTION.AutoToggle | A | 切换自动模式 |
| 隐藏对话框 | INTERNAL_ACTION.HideDialogue | 右键 / Delete | 临时隐藏对话框 |
| 重放语音 | INTERNAL_ACTION.ReplayVoice | R | 重放当前角色语音 |
订阅内置动作
import { Extension, extension, INTERNAL_ACTION } from "@avg-studio/sdk";
@extension({ id: "my-hud", label: "HUD", autonomous: true })
export class MyHud extends Extension {
static onRegister(ctx) {
ctx.input.onAction(INTERNAL_ACTION.AutoToggle, () => {
console.log("玩家切换了自动播放");
});
}
}
注册自定义动作
自定义动作会出现在 Studio 的「项目设置 → 输入按键」中:
static onRegister(ctx) {
ctx.input.registerAction({
id: "my-ext.open-inventory",
label: "打开背包",
defaultKeys: ["KeyI"],
});
ctx.input.onAction("my-ext.open-inventory", () => {
void ctx.visualUI.open("@my-ext/inventory");
});
}
自定义动作 id 必须以扩展 id 为前缀。internal.* 是引擎保留命名空间,扩展不能使用。
常量名是单数:INTERNAL_ACTION.Advance 和 INTERNAL_SYSTEM_SLOT.Title。复数形式是元数据查询表,通常不需要直接使用。