diff --git a/ROADMAP.md b/ROADMAP.md index 83baa2c..3e7a524 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1062,7 +1062,83 @@ npx @electron/packager . MyGame --platform=win32 --arch=x64 --out=release - [x] `public/scenes/demo.json` — 配置 `introVideo` / `menuVideo` - [x] 验证:TypeScript + Vite build 通过 -## 依赖清单 +### P21 菜单系统重构 — 主菜单 + 暂停菜单 + 设置 + 游戏内顶栏 ✅ 已完成 2026-06-10 + +目标:按照行业标准(Detroit / Dark Pictures / Telltale)重新整理四个菜单系统的设计和交互。 + +**现状 vs 业界差距:** + +| 菜单 | 现状 | 业界标准 | +|------|------|---------| +| 主菜单 | 两行横排 7 个按钮,LangSwitch 悬浮 | 竖排单列 4-5 项,语言在设置里,背景视频可见 | +| 游戏内顶栏 | 左侧 LangSwitch + PlaybackBar,右侧 3 个按钮 = 共 5 项 | 几乎无 HUD,仅角落菜单图标 | +| ESC 行为 | 直接打开 SaveLoadMenu | 打开暂停菜单(存档是子项) | +| 设置面板 | AccessibilitySettings 独立面板 | 设置中分类展示,**语言在设置里** | + +**四个菜单系统重新规划:** + +**1. 主菜单(MainMenu.vue 重设计)** + +``` +(menuVideo 循环播放作为背景,半透 overlay) + + [ 新游戏 ] ← 竖排,最大 + [ 继续 ] ← 可选 + + 章节选择 · 成就 · 画廊 · 设置 ← 底部小字装饰行 +``` + +- 改为竖排单列,视觉层次分明 +- LangSwitch 移除,语言挪到设置面板 +- 半透明 overlay,menuVideo 背景可透 + +**2. 游戏内顶栏(App.vue 精简)** + +``` +左:跳过(条件) · 倍速(条���) 右:全屏 · [ ≡ ] +``` + +- LangSwitch 移除 +- 设置按钮移除,统一在 ≡ 暂停菜单内 +- ≡ 按钮基于现有的"菜单"/"设置"入口替代 + +**3. ESC 暂停菜单(新建 `PauseMenu.vue`)** + +``` +(当前视频暂停,半透明遮罩覆盖) + + [ 继续游戏 ] ← 或按 Space/Esc + [ 存档 / 读档 ] + [ 设置 ] + [ 返回主菜单 ] +``` + +- 不再直接打开 SaveLoadMenu +- 第一个 Esc 打开暂停菜单,再按 Esc 继续 + +**4. 设置面板(AccessibilitySettings.vue 升级)** + +``` + 语言:中文 ▼ English ← 顶部新增 + + 字幕字号:20 ▼ + 字幕背景透明:0 ▼ + QTE 时限放宽:关/开 + QTE 按键简化:关/开 + 防误触延迟:开/关 + 可暂停:开/关 +``` + +- 语言选择下拉移到这里 + +**实现清单:** + +- [x] `src/components/PauseMenu.vue` — **新增** — ESC 暂停菜单:继续/存档/设置/返回主菜单 + 按 Esc 继续提示 +- [x] `src/components/MainMenu.vue` — 竖排单列设计:开始最大、继续次之、底部装饰行、移除 LangSwitch +- [x] `src/components/AccessibilitySettings.vue` — 顶部新增语言选择下拉(中文/English) +- [x] `src/App.vue` — 顶栏精简到跳过/倍速/全屏/≡;ESC 打开 PauseMenu 替代直接开 SaveLoadMenu;移除 LangSwitch +- [x] `src/locales/zh.json` + `en.json` — 新增 8 个 PauseMenu 专用翻译 key +- [x] 验证:TypeScript + Vite build 通过 ```json { diff --git a/src/App.vue b/src/App.vue index b348500..78d51b6 100644 --- a/src/App.vue +++ b/src/App.vue @@ -9,6 +9,7 @@ import SaveLoadMenu from '@/components/SaveLoadMenu.vue' import ChapterSelect from '@/components/ChapterSelect.vue' import PlaybackBar from '@/components/PlaybackBar.vue' import MainMenu from '@/components/MainMenu.vue' +import PauseMenu from '@/components/PauseMenu.vue' import AchievementToast from '@/components/AchievementToast.vue' import AchievementPanel from '@/components/AchievementPanel.vue' import EndingGallery from '@/components/EndingGallery.vue' @@ -27,6 +28,7 @@ const videoElB = ref(null) const loading = ref(true) const started = ref(false) const showMenu = ref(false) +const showPauseMenu = ref(false) const showChapterSelect = ref(false) const showAchievements = ref(false) const showEndingGallery = ref(false) @@ -192,9 +194,16 @@ function onGlobalKeydown(e: KeyboardEvent) { showChapterSelect.value = false } else if (showMenu.value) { showMenu.value = false + } else if (showPauseMenu.value) { + showPauseMenu.value = false + } else if (showAchievements.value) { + showAchievements.value = false + } else if (showEndingGallery.value) { + showEndingGallery.value = false + } else if (recapChapterId.value) { + recapChapterId.value = null } else if (started.value && !store.gameEnded) { - showMenu.value = true - refreshSaves() + showPauseMenu.value = true } } } @@ -210,6 +219,28 @@ function togglePause() { } } +function onPauseResume() { + showPauseMenu.value = false +} + +function onPauseSaveLoad() { + showPauseMenu.value = false + showMenu.value = true + refreshSaves() +} + +function onPauseSettings() { + showPauseMenu.value = false + store.setShowSettings(true) +} + +function onQuitToMenu() { + showPauseMenu.value = false + store.setGameEnded(true) + engine.qteSystem.cancel() + engine.audioSystem.stop(2.0) +} + function onGlobalMouseMove() { store.setInputMode('mouse') } @@ -275,18 +306,14 @@ init()
{{ promptToast }}
- - - - + +
+ import { useGameStore } from '@/stores/gameStore' +import { useI18n } from '@/composables/useI18n' const store = useGameStore() +const { currentLang, setLang } = useI18n() const emit = defineEmits<{ close: [] @@ -17,6 +19,13 @@ const bgAlphaOptions = [0, 0.3, 0.5, 0.7, 0.9]

设置

+
+ 语言 + +
字幕字号