init
This commit is contained in:
199
ROADMAP.md
Normal file
199
ROADMAP.md
Normal file
@@ -0,0 +1,199 @@
|
||||
# 交互式电影游戏引擎 — 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
|
||||
```
|
||||
|
||||
## 场景数据格式
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
目标:能播放一段视频 → 弹出选项 → 跳到下一段视频
|
||||
|
||||
- [x] 项目脚手架:Vite + Vue3 + TypeScript + Pinia
|
||||
- [x] `engine/core/Engine.ts` — 主循环骨架(加载场景 → 播放 → 等选择 → 切换)
|
||||
- [x] `engine/core/SceneManager.ts` — 加载 JSON,按 ID 查找场景节点
|
||||
- [x] `engine/core/VideoManager.ts` — 单 video 元素播放,监听 ended 事件
|
||||
- [x] `engine/core/StateManager.ts` — 变量存取、条件求值、效果执行
|
||||
- [x] `engine/types.ts` — 类型定义
|
||||
- [x] `src/components/GamePlayer.vue` — 挂载 video,控制播放
|
||||
- [x] `src/components/ChoicePanel.vue` — 渲染选择按钮,触发引擎切换
|
||||
- [x] `public/scenes/demo.json` — 编写一段简单剧情(7 个场景节点)
|
||||
- [x] 验证:从 demo.json 加载场景,能走通 开始→选择→分支播放→结束 流程
|
||||
|
||||
### P1 核心 — 无缝切换 + 条件分支 + 存档(1-2 周)
|
||||
|
||||
- [ ] `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` — 存档/读档 UI
|
||||
- [ ] `src/stores/gameStore.ts` — Pinia 全局状态管理
|
||||
- [ ] `src/composables/` — 三个 composable 桥接层
|
||||
- [ ] 验证:分支剧情走通,存档读档正常,视频切换无明显黑屏
|
||||
|
||||
### P2 进阶 — QTE + 字幕 + 多存档槽(1 周)
|
||||
|
||||
- [ ] `engine/systems/QTESystem.ts` — QTE 触发、键盘监听、超时判定
|
||||
- [ ] `src/components/QTEOverlay.vue` — QTE 视觉遮罩(按键提示 + 倒计时环)
|
||||
- [ ] `src/components/Subtitles.vue` — WebVTT 解析 + 字幕渲染
|
||||
- [ ] 多存档槽位 + 存档缩略图(canvas 截图当前视频帧)
|
||||
- [ ] `engine/core/Engine.ts` — 完整事件总线(sceneChange, choiceMade, qteTriggered 等)
|
||||
- [ ] 验证:QTE 正常触发与判定,字幕同步,多存档正常工作
|
||||
|
||||
### P3 编辑器 — 可视化剧情编辑(2-3 周)
|
||||
|
||||
- [ ] 编辑器入口:独立 `editor/index.html` + `editor/main.ts`
|
||||
- [ ] `editor/components/SceneGraph.vue` — Vue Flow 节点图(节点=场景,边=选择分支)
|
||||
- [ ] `editor/components/NodeEditor.vue` — 右侧面板,编辑选中节点的视频、选项、QTE、条件/效果
|
||||
- [ ] `editor/components/PreviewPanel.vue` — 嵌入播放器,实时预览当前编辑的剧情线
|
||||
- [ ] `editor/composables/useGraphEditor.ts` — 图数据与 JSON 双向同步
|
||||
- [ ] JSON 导出/导入
|
||||
- [ ] 验证:编辑器能产出合法 JSON,引擎能正确加载并运行
|
||||
|
||||
## 依赖清单
|
||||
|
||||
```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"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 关键架构决策记录
|
||||
|
||||
1. **引擎与 UI 分离**: `engine/` 下纯 TS 类,不 import Vue。UI 层通过 composables 桥接。
|
||||
2. **A/B 双缓冲**: 两个 `<video>` 元素轮换,一个播放时另一个预加载候选视频。
|
||||
3. **JSON 驱动**: 所有剧情数据放在 JSON 中,编辑器本质是 JSON 的可视化读写工具。
|
||||
4. **IndexedDB 存档**: 比 localStorage 容量大,可存储截屏缩略图。
|
||||
Reference in New Issue
Block a user