161 lines
5.1 KiB
Markdown
161 lines
5.1 KiB
Markdown
# 剧情编辑器
|
||
|
||
基于 Vue Flow 的可视化交互式电影剧情编辑工具,通过拖拽节点和连线来编排游戏场景和分支。
|
||
|
||
## 启动
|
||
|
||
```bash
|
||
npm install
|
||
npm run dev
|
||
```
|
||
|
||
浏览器打开 `http://localhost:5173/editor/`
|
||
|
||
## 界面布局
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────┐
|
||
│ 工具栏: 新建 / 导入导出 / 加载示例 / 起始场景 │
|
||
├────────────────────┬──────────────┬───────────────┤
|
||
│ │ │ │
|
||
│ 场景节点图 │ 属性编辑面板 │ 视频预览 │
|
||
│ (Vue Flow) │ │ │
|
||
│ │ │ │
|
||
└────────────────────┴──────────────┴───────────────┘
|
||
```
|
||
|
||
## 基本操作
|
||
|
||
### 场景节点图(左侧)
|
||
|
||
- **点击节点** → 右侧面板打开该场景的属性编辑器
|
||
- **拖拽节点端口到另一个节点** → 创建"选项"连线(自动生成选项文本)
|
||
- **缩放/平移**:鼠标滚轮缩放,拖拽画布平移
|
||
|
||
### 新建场景
|
||
|
||
点击工具栏 `+ 新场景`,生成一个新节点并自动选中。
|
||
|
||
### 编辑场景(右侧面板选中节点后)
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| 视频路径 | 该场景对应的视频文件,如 `/videos/scene_1.mp4` |
|
||
| 字幕路径 | 可选 WebVTT 字幕文件,如 `/subtitles/scene_1.vtt` |
|
||
| 默认下一场景 | 没有选项或选项超时后的自动跳转目标 |
|
||
| QTE | 快速反应事件:触发时间、提示文字、按键、限时、成功/失败跳转 |
|
||
| 选项列表 | 玩家可见的分支选项,包含文字、目标场景、限时 |
|
||
|
||
### 选项管理
|
||
|
||
- 点击 `+ 添加选项` 增加新选项
|
||
- 填写选项文字和目标场景
|
||
- 可设置限时(秒),超时自动选第一项
|
||
- 点 × 删除选项
|
||
|
||
### 删除场景
|
||
|
||
编辑器面板标题栏点击 🗑 按钮,会同时清理其他场景中指向该场景的引用。
|
||
|
||
## 数据管理
|
||
|
||
### 加载示例
|
||
|
||
点击 `加载示例` 载入 `public/scenes/demo.json`,了解数据格式。
|
||
|
||
### 导入 / 导出 JSON
|
||
|
||
- **导出**:将当前编辑的剧情导出为 JSON 文件
|
||
- **导入**:从 JSON 文件加载剧情数据
|
||
|
||
JSON 格式与游戏引擎的数据结构一致:
|
||
|
||
```json
|
||
{
|
||
"startScene": "scene_1",
|
||
"variables": {},
|
||
"scenes": {
|
||
"scene_1": {
|
||
"id": "scene_1",
|
||
"videoUrl": "/videos/scene_1.mp4",
|
||
"choices": [
|
||
{ "text": "进入房间", "targetScene": "scene_2" }
|
||
],
|
||
"nextScene": "",
|
||
"subtitleUrl": "",
|
||
"onEnter": []
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
导出的 JSON 可直接放入 `public/scenes/` 目录供游戏引擎加载。
|
||
|
||
## 场景数据结构
|
||
|
||
```ts
|
||
interface SceneNode {
|
||
id: string // 唯一标识
|
||
videoUrl: string // 视频文件路径
|
||
subtitleUrl?: string // 字幕文件路径(可选)
|
||
choices?: Choice[] // 选项列表
|
||
qte?: QTEDefinition // QTE 快速反应事件(可选)
|
||
nextScene?: string // 默认跳转场景
|
||
onEnter?: Effect[] // 进入场景时触发的效果
|
||
}
|
||
|
||
interface Choice {
|
||
text: string // 选项文字
|
||
targetScene: string // 目标场景 ID
|
||
conditions?: Condition[] // 显示条件(可选)
|
||
effects?: Effect[] // 触发效果(可选)
|
||
timeLimit?: number // 限时秒数,0=不限
|
||
}
|
||
```
|
||
|
||
## 图布局
|
||
|
||
场景节点图使用 [dagre](https://github.com/dagrejs/dagre) 进行层级化自动布局。
|
||
|
||
### 布局策略演进
|
||
|
||
| 版本 | 方式 | 问题 |
|
||
|------|------|------|
|
||
| v1 | 网格排列 `(i % 4) * 220` | 不反映拓扑关系 |
|
||
| v2 | BFS 层级分配 | 多父同子时边交叉严重 |
|
||
| v3 (当前) | Dagre (Sugiyama 算法) | — |
|
||
|
||
Dagre 自动处理:
|
||
|
||
- **层内排序** — Barycenter 启发式最小化边交叉
|
||
- **多父同子** — 插入虚拟节点,边不交织
|
||
- **回边处理** — 循环引用自动反向路由
|
||
- **间距优化** — 根据节点度自适应分布
|
||
|
||
### 配置
|
||
|
||
布局参数在 `editor/composables/useLayout.ts`:
|
||
|
||
| 参数 | 值 | 说明 |
|
||
|------|-----|------|
|
||
| `rankdir` | `'LR'` | 左→右方向 |
|
||
| `nodesep` | `50` | 同层节点垂直间距(px) |
|
||
| `ranksep` | `240` | 层级间水平间距(px) |
|
||
| `marginx` / `marginy` | `60` | 画布四周边距(px) |
|
||
| `NODE_W` / `NODE_H` | `180 × 60` | 节点尺寸,用于居中偏移 |
|
||
|
||
### 连线样式
|
||
|
||
- 边类型:`SmoothStepEdge`(正交线,拐角带圆角),在 `SceneGraph.vue` 通过 `:default-edge-type="SmoothStepEdge"` 全局设置
|
||
- 动画:已禁用
|
||
- 回边:Dagre 自动路由,Vue Flow 渲染为从右往左的回线
|
||
|
||
### 调参指南
|
||
|
||
| 现象 | 调整 |
|
||
|------|------|
|
||
| 节点堆叠拥挤 | 增大 `nodesep` / `ranksep` |
|
||
| 节点间距过大 | 减小 `ranksep` |
|
||
| 边碰到画布边缘 | 增大 `marginx` / `marginy` |
|
||
| 节点定位偏左/上 | 检查 `NODE_W` / `NODE_H` 是否匹配实际节点尺寸 |
|