feat: electron packaging, build scripts, gitignore and docs update

This commit is contained in:
2026-06-09 23:53:32 +08:00
parent 48fb89449a
commit 25d73f5443
7 changed files with 260 additions and 94 deletions

197
README.md
View File

@@ -1,142 +1,153 @@
# 交互式电影游戏引擎
基于 Vue 3 + TypeScript 的浏览器端交互式电影游戏引擎。
**零代码门槛**:你只需要会剪视频和写 JSON不需要前端知识。
## 快速开始
```bash
git clone <repo-url> mygame
cd mygame
npm install
npm run dev
```
浏览器打开 `http://localhost:5173/` 即可体验示例剧情。
打开 `http://localhost:5173/`,你会看到示例剧情。
## 如何使用
## 制作你的游戏
### 1. 编写剧情 JSON
### 1. 准备素材
`public/scenes/` 目录下创建 JSON 文件,定义你的场景和分支:
| 素材 | 目录 | 格式要求 |
|------|------|---------|
| 视频文件 | `public/videos/` | MP4 (H.264)1280×72030fps2-5Mbps |
| 背景音乐 | `public/audio/` | MP3 |
| 缩略图 | `public/images/` | JPG/PNG320×180 |
| 字幕 | `public/subtitles/` | WebVTT (.vtt) |
> `public/videos/` 已在 `.gitignore` 中,视频文件不需要提交到 Git。
### 2. 编写剧情 JSON
编辑 `public/scenes/demo.json`,定义你的场景和分支。**最小可玩示例只需 20 行 JSON**
```json
{
"startScene": "scene_1",
"variables": {
"trust": 50,
"courage": 0
},
"startScene": "intro",
"variables": { "trust": 50 },
"scenes": {
"scene_1": {
"id": "scene_1",
"videoUrl": "/videos/scene_1.mp4",
"intro": {
"id": "intro",
"videoUrl": "/videos/intro.mp4",
"choices": [
{
"text": "打开左边的门",
"targetScene": "scene_2a",
"effects": [
{ "type": "add", "target": "courage", "value": 10 }
]
},
{
"text": "打开右边的门",
"targetScene": "scene_2b"
}
{ "text": "帮助他", "targetScene": "help_end" },
{ "text": "离开", "targetScene": "leave_end" }
]
},
"scene_2a": {
"id": "scene_2a",
"videoUrl": "/videos/scene_2a.mp4",
"nextScene": "ending"
},
"scene_2b": {
"id": "scene_2b",
"videoUrl": "/videos/scene_2b.mp4",
"help_end": {
"id": "help_end",
"videoUrl": "/videos/help.mp4",
"choices": []
},
"ending": {
"id": "ending",
"videoUrl": "/videos/ending.mp4",
"leave_end": {
"id": "leave_end",
"videoUrl": "/videos/leave.mp4",
"choices": []
}
}
}
```
**字段说明:**
完整字段参考见 **[docs/SCENE_JSON_SPEC.md](docs/SCENE_JSON_SPEC.md)**。
| 字段 | 说明 |
|------|------|
| `startScene` | 游戏开始的场景 ID |
| `variables` | 全局变量初始值(如好感度、勇气值) |
| `scenes` | 所有场景节点key 为场景 ID |
| `videoUrl` | 视频文件路径,放在 `public/videos/` 下 |
| `choices` | 选项列表,为空或不存在时视为结局 |
| `nextScene` | 没有选项时的默认下一场景(自动跳转) |
| `effects` | 选择后的效果,类型: `set`/`add`/`toggleFlag` |
| `conditions` | 选项的显示条件(`==`, `!=`, `>`, `<`, `>=`, `<=`, `hasFlag` |
### 2. 放置视频文件
将视频文件放入 `public/videos/` 目录,推荐 MP4 (H.264) 格式。
生成测试视频(需要 ffmpeg
### 3. 实时预览
```bash
ffmpeg -f lavfi -i "color=c=0x1a1a2e:s=1280x720:d=3" \
-vf "drawtext=text='章节标题':fontcolor=white:fontsize=32:x=(w-text_w)/2:y=(h-text_h)/2" \
public/videos/scene_1.mp4
npm run dev
```
### 3. 修改加载的剧情文件
Vite 会启动热重载服务器,修改 JSON 或视频后自动刷新。
`src/App.vue` 中修改 `loadGame()` 的路径:
### 4. 可视化编辑剧情
```ts
await loadGame('/scenes/your_story.json')
浏览器打开 `http://localhost:5173/editor/`,可以用节点图编辑器拖拽编辑场景分支。
## 打包发布
```bash
npm run pack:html # Web 版 → release/mygame.zip → 上传 itch.io / Netlify
npm run pack:mac # macOS → release/MyGame-darwin-arm64/
npm run pack:win # Windows → release/MyGame-win32-x64/
```
打包前会自动验证 JSON 合法性。
## 引擎功能
| 功能 | 说明 |
|------|------|
| 视频分支播放 | A/B 双缓冲无缝切换300ms 交叉淡化 |
| 选择系统 | 限时选择、条件分支(根据变量显示/隐藏选项) |
| QTE 快速反应事件 | 视频中插入限时按键挑战,成功/失败跳转不同场景 |
| 图片/视频热点 | 点击画面区域触发分支,视频热点按时间轴显隐 |
| 循环等待 | 视频结束后自动循环指定片段,保持画面动态 |
| 独立 BGM | 背景音乐独立驱动,场景切换时交叉淡化,不受画面循环影响 |
| BGM Ducking | 选择/QTE/热点出现时 BGM 自动降低音量 |
| 字幕系统 | WebVTT 解析,多语言字幕切换 |
| 章节系统 | 分章节管理剧情,到达即解锁,可跳转 |
| 成就系统 | 变量满足条件时自动解锁,底部弹窗提示 |
| 结局画廊 | 所有结局缩略图展示,已解锁/未解锁状态 |
| 章节回顾 | 每章完成度百分比 + 未解锁分支条件提示 |
| 关键选择提示 | 重要选项前置金色标识 + 选后浮现提示文字 |
| 跳过已看 + 倍速 | 已看场景可跳过1x/2x/4x 倍速播放 |
| 全屏模式 | 一键全屏沉浸式浏览器体验 |
| 键盘导航 | 方向键选选项Esc 菜单Space 暂停 |
| 多语言 i18n | UI + 字幕支持中英文切换 |
| 可访问性 | 字幕字号/背景、QTE 时限放宽/按键简化、防误触延迟 |
| 存档系统 | IndexedDB 多槽位,跨会话持久化 |
## 目录结构
```
moviegame/
├── engine/ # 框架无关的核心引擎(不依赖 Vue
│ ├── core/
│ ├── Engine.ts # 主循环
│ │ ├── SceneManager.ts # 场景管理
│ │ ├── VideoManager.ts # 视频播放控制
│ │ └── StateManager.ts # 状态/变量/条件系统
mygame/
├── engine/ # 引擎核心(纯 TS不依赖 Vue
│ ├── core/ # Engine / VideoManager / StateManager / SceneManager
│ ├── systems/ # QTE / Choice / Audio / Achievement / Save
│ └── types.ts # 类型定义
├── src/ # Vue 播放器
│ ├── components/
│ ├── GamePlayer.vue # 视频播放器
│ └── ChoicePanel.vue # 选项面板
── composables/
└── useGameEngine.ts # 引擎 ↔ Vue 桥接
│ ├── stores/
└── gameStore.ts # Pinia 状态
│ ├── App.vue
── main.ts
├── public/
│ ├── scenes/demo.json # 示例剧情
│ └── videos/ # 视频资源
├── ROADMAP.md # 开发路线图
└── package.json
├── src/ # Vue UI 层
│ ├── components/ # 所有界面组件
│ ├── composables/ # 引擎 ↔ UI 桥接
├── stores/ # Pinia 状态管理
── locales/ # 翻译文件zh.json / en.json
├── editor/ # 可视化剧情编辑器
├── electron/ # 桌面应用打包Electron
├── public/ # 你的素材
│ ├── videos/ # 视频文件(.mp4
── audio/ # 背景音乐(.mp3
│ ├── images/ # 缩略图
│ ├── subtitles/ # 字幕(.vtt
│ └── scenes/demo.json # 剧情定义
├── docs/ # 文档
│ └── SCENE_JSON_SPEC.md # JSON 完整字段参考
├── scripts/ # 打包脚本
└── ROADMAP.md # 开发路线图
```
## 当前状态
## 视频制作建议
**已完成 (P0 MVP)** 单视频播放 + 选项分支 + 状态系统 + JSON 驱动
| 参数 | 建议值 |
|------|--------|
| 视频不包含 BGM | 背景音乐用独立 .mp3 文件 + `bgmUrl` 字段,画面循环时 BGM 不中断 |
| 循环片段 | 正文段 + 循环段合成为一个文件,用 `loopStart`/`loopEnd` 标记 |
| 字幕 | WebVTT 格式,时间轴精确到毫秒 |
**下一步 (P1)** A/B 双缓冲无缝切换、条件分支、IndexedDB 存档系统
详见 [ROADMAP.md](ROADMAP.md)。
## 命令
## 命令参考
```bash
npm run dev # 启动开发服务器
npm run build # 构建生产版本
npm run preview # 预览构建结果
npm run dev # 启动开发服务器(实时预览)
npm run build # 构建生产版本
npm run preview # 预览构建结果
npm run pack:html # 打包 Web 版
npm run pack:mac # 打包 macOS 桌面应用
npm run pack:win # 打包 Windows 桌面应用
```
## 使用提示
场景虽然支持图片但是图片场景容易触发一些bug,所以建议只使用视频场景这样可以避免遇到没有测试覆盖的bug也能简化引擎的逻辑。