Files
tianshu-engine/docs/guide/SCENE_JSON_SPEC.md

298 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Scene JSON 完整字段参考
## 顶层结构
```json
{
"assetBase": "",
"locales": { "path": "locales/", "languages": ["zh", "en"] },
"startScene": "intro",
"variables": { "trust": 50, "courage": 0 },
"introVideo": "__intro__/logo.mp4",
"menuVideo": "__intro__/menu_bg.mp4",
"scenes": { ... },
"chapters": [ ... ],
"achievements": [ ... ],
"endings": [ ... ]
}
```
| 字段 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `assetBase` | string | 否 | 所有资源路径前缀,默认 `""`。设 `"demo/"``videoUrl: "intro/video.mp4"` 自动拼成 `demo/intro/video.mp4`。改 CDN 只需改这一行 |
| `locales` | object | 否 | 多语言配置。`path` 为 locale 文件目录(相对于 `assetBase``languages` 为支持的语言列表 |
| `startScene` | string | 是 | 开始场景的 ID |
| `variables` | object | 否 | 全局变量初始值 |
| `introVideo` | string | 否 | 开场视频路径 |
| `menuVideo` | string | 否 | 主菜单背景视频路径(自动循环播放) |
| `scenes` | object | 是 | 所有场景的集合key 为场景 ID |
| `chapters` | array | 否 | 章节列表 |
| `achievements` | array | 否 | 成就列表 |
| `endings` | array | 否 | 结局列表 |
---
## SceneNode
```typescript
interface SceneNode {
id: string
type?: 'video' | 'image'
videoUrl: string
streamingUrl?: Record<string, string>
imageUrl?: string
thumbnail?: string
contentSize?: { w: number; h: number }
subtitleUrl?: string
subtitles?: Record<string, string>
choices?: Choice[]
hotspots?: Hotspot[]
qte?: QTEDefinition
nextScene?: string
onEnter?: Effect[]
loopStart?: number
loopEnd?: number
bgmUrl?: string
bgmVolume?: number
bgmCrossFade?: number
bgmDuckLevel?: number
bgmDuckFade?: number
videoMuted?: boolean
skippable?: boolean
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | string | 场景唯一标识 |
| `type` | string | `"video"` (默认) 或 `"image"`。image 类型展示图片+热点,不播放视频 |
| `videoUrl` | string | 视频文件路径(本地 MP4桌面版使用。image 场景可为空 |
| `streamingUrl` | object | Web 版使用的 CDN 流媒体路径。三档画质:`{ "超清 (1080P)": "...", "高清 (720P)": "...", "标清 (480P)": "..." }`。引擎根据 `getVideoMode()` 自动选择环境 |
| `imageUrl` | string | 图片场景的图片路径 |
| `thumbnail` | string | 场景缩略图路径 |
| `contentSize` | object | 内容基准分辨率 `{ w: 1280, h: 720 }`Hotspot 坐标基于此计算。用于 object-fit: contain 的偏移补偿 |
| `subtitleUrl` | string | 回退字幕路径。优先使用 `subtitles` |
| `subtitles` | object | 多语言字幕 `{ "zh": "...", "en": "..." }`。语言切换时自动选择 |
| `choices` | Choice[] | 选项列表 |
| `hotspots` | Hotspot[] | 可点击热点区域 |
| `qte` | QTEDefinition | QTE 定义 |
| `nextScene` | string | 无选项时的默认跳转场景 |
| `onEnter` | Effect[] | 进入场景时触发的效果 |
| `loopStart` | number | 循环起始时间(秒) |
| `loopEnd` | number | 循环结束时间(秒)。视频播放到 loopEnd 时跳回 loopStart |
| `bgmUrl` | string | 背景音乐路径 |
| `bgmVolume` | number | 背景音乐音量0-1默认 0.8 |
| `bgmCrossFade` | number | 背景音乐交叉淡化时长(秒),默认 2.0 |
| `bgmDuckLevel` | number | BGM Duck 压低比例0-1默认 0.35 |
| `bgmDuckFade` | number | BGM Duck 过渡时长(秒),默认 0.5 |
| `videoMuted` | boolean | 视频静音(配合独立 BGM 使用) |
| `skippable` | boolean | `false` = 禁止跳过(用于 QTE 等关键场景) |
---
## Choice
```typescript
interface Choice {
text: string
textKey?: string
prompt?: string
promptKey?: string
targetScene: string
conditions?: Condition[]
effects?: Effect[]
timeLimit?: number
}
```
| 字段 | 说明 |
|------|------|
| `text` | 选项文本(回退值) |
| `textKey` | i18n key优先于 `text`。如 `"intro.choice.left_door"` |
| `prompt` | 选择后浮现的提示文字(回退值) |
| `promptKey` | prompt 的 i18n key。如 `"left_door.prompt.handshake"`。优先于 `prompt` |
| `promptKey` | prompt 的 i18n key。如 `"left_door.prompt.handshake"` |
| `targetScene` | 目标场景 ID |
| `conditions` | 显示条件,不满足的选项隐藏 |
| `effects` | 选择后触发的效果 |
| `timeLimit` | 限时秒数0=不限时 |
---
## Hotspot
```typescript
interface Hotspot {
id: string
label: string
labelKey?: string
targetScene: string
x: number
y: number
width: number
height: number
showAt?: number
hideAt?: number
conditions?: Condition[]
effects?: Effect[]
timeLimit?: number
}
```
| 字段 | 说明 |
|------|------|
| `id` | 热点唯一标识 |
| `label` | 显示标签(回退值) |
| `labelKey` | i18n key |
| `x, y` | 左上角坐标(像素,基于 contentSize |
| `width, height` | 尺寸(像素) |
| `showAt` | 视频时间(秒),此时间后显示。不设则始终可见 |
| `hideAt` | 视频时间(秒),此时间后隐藏 |
| `targetScene` | 点击后跳转的场景 |
| `conditions` | 显示条件 |
| `effects` | 点击后触发的效果 |
| `timeLimit` | 限时热点(秒),超时后热点消失 |
---
## QTEDefinition
```typescript
interface QTEDefinition {
triggerTime: number
prompt: string
promptKey?: string
keys: string[]
timeLimit: number
successScene: string
failScene: string
effects?: {
success: Effect[]
fail: Effect[]
}
}
```
| 字段 | 说明 |
|------|------|
| `triggerTime` | 触发时间(秒),视频播放到此时间弹出 QTE |
| `prompt` | 提示文字(回退值) |
| `promptKey` | i18n key。如 `"right_door.qte.dodge"`。优先于 `prompt` |
| `promptKey` | i18n key。如 `"right_door.qte.dodge"` |
| `keys` | 有效按键列表,如 `["ArrowLeft", "ArrowRight", "a", "d"]` |
| `timeLimit` | 限时秒数 |
| `successScene` | 成功跳转场景 |
| `failScene` | 失败/超时跳转场景 |
| `effects` | 成功/失败分别触发效果 |
---
## 其他类型
### Condition
```typescript
interface Condition {
variable: string
op: '>' | '<' | '>=' | '<=' | '==' | '!='
value: number | string | boolean
}
```
### Effect
```typescript
interface Effect {
type: 'set' | 'add'
target: string
value?: number | string | boolean
}
```
- `set` — 设置变量值
- `add` — 变量增加/减少
### ChapterInfo
```typescript
interface ChapterInfo {
id: string
label: string
labelKey?: string
startScene: string
thumbnail?: string
defaultVariables?: Record<string, number>
}
```
| 字段 | 说明 |
|------|------|
| `id` | 章节 ID |
| `label` | 章节名称(回退值) |
| `labelKey` | i18n key优先于 `label` |
| `startScene` | 起始场景 ID。玩家到达此场景时章节自动解锁 |
| `thumbnail` | 缩略图路径 |
| `defaultVariables` | 从章节选择界面进入时的默认变量值。未设时 fallback 到全局 `variables` |
### AchievementDef
```typescript
interface AchievementDef {
id: string
title: string
titleKey?: string
description: string
descKey?: string
icon?: string
hidden?: boolean
condition: Condition
}
```
| 字段 | 说明 |
|------|------|
| `id` | 成就唯一 ID |
| `title` | 成就标题(回退值) |
| `titleKey` | i18n key优先于 `title` |
| `description` | 成就描述(回退值) |
| `descKey` | i18n key优先于 `description` |
| `icon` | 图标路径 |
| `hidden` | `true` 时未解锁不显示标题和描述(显示 ??? |
| `condition` | 解锁条件。变量满足时自动解锁并弹出 toast |
### EndingDef
```typescript
interface EndingDef {
id: string
label: string
labelKey?: string
sceneId: string
chapterId?: string
thumbnail?: string
}
```
| 字段 | 说明 |
|------|------|
| `id` | 结局唯一 ID |
| `label` | 结局名称(回退值) |
| `labelKey` | i18n key优先于 `label` |
| `sceneId` | 结局场景 ID。玩家到达此场景时结局自动标记已解锁 |
| `chapterId` | 结局归属章节 ID可选BFS 自动推导) |
| `thumbnail` | 缩略图路径 |
### LocalesConfig
```typescript
interface LocalesConfig {
path: string
languages: string[]
}
```
| 字段 | 说明 |
|------|------|
| `path` | 语言文件目录(相对于 `assetBase`),如 `"locales/"` |
| `languages` | 支持的语言列表,如 `["zh", "en", "ja"]` |