- editor/: stand-alone Vite multi-page app for visual scenario editing - editor/components/SceneGraph.vue: Vue Flow graph with scene nodes, branch/default/QTE edges - editor/components/NodeEditor.vue: right panel editing video/subtitle paths, choices, QTE params - editor/components/PreviewPanel.vue: embedded video player previewing selected scene - editor/composables/useGraphEditor.ts: bidirectional graph<->JSON sync - editor/App.vue: toolbar (new scene, import/export JSON, load demo, start scene selector) - @vue-flow/core|background|controls: graph visualization dependencies - vite.config.ts: multi-page build (main + editor) - ROADMAP: mark P3 as completed
8.1 KiB
8.1 KiB
交互式电影游戏引擎 — Roadmap
技术栈
- 框架: Vue 3 (Composition API +
<script setup>) - 构建: Vite
- 状态管理: Pinia
- 可视化编辑器: Vue Flow
- 存储: IndexedDB (Dexie.js)
- 语言: TypeScript
- 视频: 原生
<video>+ A/B 双缓冲
项目结构
moviegame/
├── engine/ # 框架无关的核心引擎(纯 TS)
│ ├── core/
│ │ ├── Engine.ts # 主循环,驱动各子系统
│ │ ├── SceneManager.ts # 剧情节点图遍历
│ │ ├── VideoManager.ts # A/B 双缓冲视频播放
│ │ └── StateManager.ts # 全局状态、条件求值
│ ├── systems/
│ │ ├── ChoiceSystem.ts # 选择 UI + 倒计时
│ │ ├── QTESystem.ts # QTE 触发、判定、超时
│ │ └── SaveSystem.ts # IndexedDB 存取
│ └── types.ts # 场景数据类型定义
├── src/ # Vue 应用(播放器端)
│ ├── components/
│ │ ├── GamePlayer.vue # 主播放器(挂载 video 元素)
│ │ ├── ChoicePanel.vue # 选项面板
│ │ ├── QTEOverlay.vue # QTE 遮罩
│ │ ├── SaveLoadMenu.vue # 存档界面
│ │ └── Subtitles.vue # 字幕显示
│ ├── composables/
│ │ ├── useGameEngine.ts # 引擎实例 + 生命周期
│ │ ├── useVideoPlayer.ts # 视频状态响应式封装
│ │ └── useGameState.ts # 状态响应式封装
│ ├── stores/
│ │ └── gameStore.ts # 游戏全局状态(Pinia)
│ ├── App.vue
│ └── main.ts
├── editor/ # Vue Flow 可视化编辑器(独立入口)
│ ├── components/
│ │ ├── SceneGraph.vue
│ │ ├── NodeEditor.vue
│ │ └── PreviewPanel.vue
│ ├── composables/
│ │ └── useGraphEditor.ts
│ └── App.vue
├── public/
│ ├── videos/ # 视频资源
│ └── scenes/
│ └── demo.json # 示例剧情数据
├── vite.config.ts
├── tsconfig.json
├── package.json
└── index.html
场景数据格式
// engine/types.ts
interface SceneNode {
id: string;
videoUrl: string;
subtitleUrl?: string;
choices?: Choice[];
qte?: QTEDefinition;
nextScene?: string;
onEnter?: Effect[];
}
interface Choice {
text: string;
targetScene: string;
conditions?: Condition[];
effects?: Effect[];
timeLimit?: number; // 限时选择(秒),0=不限时
}
interface Condition {
variable: string;
op: '>' | '<' | '>=' | '<=' | '==' | '!=' | 'hasFlag';
value: number | string | boolean;
}
interface Effect {
type: 'set' | 'add' | 'toggleFlag' | 'triggerEvent';
target: string;
value?: number | string | boolean;
}
interface QTEDefinition {
triggerTime: number;
prompt: string;
keys: string[];
timeLimit: number;
successScene: string;
failScene: string;
effects?: {
success: Effect[];
fail: Effect[];
};
}
interface GameData {
scenes: Record<string, SceneNode>;
startScene: string;
variables: Record<string, number>;
}
interface SaveData {
slot: number;
timestamp: number;
currentScene: string;
variables: Record<string, number>;
flags: string[];
history: ChoiceRecord[];
thumbnail?: string;
}
实现路线
P0 MVP — 最小可玩原型(3-5 天)✅ 已完成 2026-06-07
目标:能播放一段视频 → 弹出选项 → 跳到下一段视频
- 项目脚手架:Vite + Vue3 + TypeScript + Pinia
engine/core/Engine.ts— 主循环骨架(加载场景 → 播放 → 等选择 → 切换)engine/core/SceneManager.ts— 加载 JSON,按 ID 查找场景节点engine/core/VideoManager.ts— 单 video 元素播放,监听 ended 事件engine/core/StateManager.ts— 变量存取、条件求值、效果执行engine/types.ts— 类型定义src/components/GamePlayer.vue— 挂载 video,控制播放src/components/ChoicePanel.vue— 渲染选择按钮,触发引擎切换public/scenes/demo.json— 编写一段简单剧情(7 个场景节点)- 验证:从 demo.json 加载场景,能走通 开始→选择→分支播放→结束 流程
P1 核心 — 无缝切换 + 条件分支 + 存档(1-2 周)✅ 已完成 2026-06-07
engine/core/VideoManager.ts升级 — A/B 双缓冲,预加载候选视频,CSS 交叉淡化engine/core/SceneManager.ts升级 — 支持条件分支(根据 variables/flags 过滤选项)engine/systems/SaveSystem.ts— Dexie.js IndexedDB 存取,多槽位engine/systems/ChoiceSystem.ts— 限时选择倒计时,超时默认选择src/components/SaveLoadMenu.vue— 存档/读档 UIsrc/stores/gameStore.ts— Pinia 全局状态管理(含计时器、存档列表)src/composables/useGameEngine.ts— 桥接层(双 video、存档、计时器)src/components/GamePlayer.vue— 双 video 元素 + 交叉淡化 CSSsrc/components/ChoicePanel.vue— 倒计时进度条 + 计时文字src/App.vue— 整合 SaveLoadMenu、双 video、计时器- 验证:条件分支走通,存档读档正常,视频切换交叉淡化
P2 进阶 — QTE + 字幕 + 多存档槽(1 周)✅ 已完成 2026-06-07
engine/systems/QTESystem.ts— QTE 触发、键盘监听(支持多键匹配)、超时判定src/components/QTEOverlay.vue— SVG 倒计时环 + 按键提示 + 成功/失败动画src/components/Subtitles.vue— WebVTT 解析 + 字幕同步渲染engine/core/Engine.ts— 集成 QTE(timeupdate 检测 + 条件跳转 + 效果应用)- 多存档槽位 + 存档缩略图(canvas 截图当前视频帧,320x180 JPEG)
engine/core/VideoManager.ts— 新增getActiveVideoElement()供截图engine/systems/SaveSystem.ts— DB 版本升级 v2(支持 thumbnail 字段)src/components/SaveLoadMenu.vue— 存档缩略图预览- 完整事件总线(sceneChange, choiceRequest, choiceTimer, choiceTimeout, videoEnd, qteTrigger, qteTimer, qteResult, gameEnd)
- 验证:QTE 正常触发与判定(ArrowLeft/ArrowRight/A/D 躲石块),字幕同步,存档缩略图正常
P3 编辑器 — 可视化剧情编辑(2-3 周)✅ 已完成 2026-06-07
- 编辑器入口:独立
editor/index.html+editor/main.ts(Vite 多入口构建) editor/components/SceneGraph.vue— Vue Flow 节点图(场景节点 + 分支/默认/QTE 连线)editor/components/NodeEditor.vue— 右侧面板(视频/字幕路径、nextScene、选项增删改、QTE 参数编辑)editor/components/PreviewPanel.vue— 嵌入播放器实时预览选中场景视频editor/composables/useGraphEditor.ts— 图数据与 JSON 双向同步- JSON 导出/导入(文件下载 + 文件选择)
- 工具栏:新建场景、导入 JSON、导出 JSON、加载示例、起始场景选择
vite.config.ts— 多页面构建(main + editor)- 验证:编辑器能产出合法 JSON,引擎能正确加载并运行
依赖清单
{
"dependencies": {
"vue": "^3.4",
"pinia": "^2.1",
"@vue-flow/core": "^1.x",
"@vue-flow/background": "^1.x",
"@vue-flow/controls": "^1.x",
"dexie": "^4.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0",
"typescript": "^5.3",
"vite": "^5.0",
"vue-tsc": "^2.0"
}
}
关键架构决策记录
- 引擎与 UI 分离:
engine/下纯 TS 类,不 import Vue。UI 层通过 composables 桥接。 - A/B 双缓冲: 两个
<video>元素轮换,一个播放时另一个预加载候选视频。 - JSON 驱动: 所有剧情数据放在 JSON 中,编辑器本质是 JSON 的可视化读写工具。
- IndexedDB 存档: 比 localStorage 容量大,可存储截屏缩略图。