feat: accessibility settings, subtitle/QTE improvements, docs update

This commit is contained in:
2026-06-09 19:42:08 +08:00
parent 33ad26ed52
commit c9d29019a0
8 changed files with 387 additions and 11 deletions

View File

@@ -13,6 +13,7 @@ import AchievementToast from '@/components/AchievementToast.vue'
import AchievementPanel from '@/components/AchievementPanel.vue'
import EndingGallery from '@/components/EndingGallery.vue'
import ChapterRecap from '@/components/ChapterRecap.vue'
import AccessibilitySettings from '@/components/AccessibilitySettings.vue'
import { useGameEngine } from '@/composables/useGameEngine'
import { useGameStore } from '@/stores/gameStore'
import { useFullscreen } from '@/composables/useFullscreen'
@@ -33,6 +34,7 @@ const recapChapterId = ref<string | null>(null)
const hasAutoSave = ref(false)
const currentSpeed = ref(1)
const canSkip = ref(false)
const paused = ref(false)
const promptToast = ref('')
const showPromptToast = ref(false)
@@ -49,14 +51,21 @@ async function init() {
function handleStart() {
started.value = true
applyQteParams()
start()
}
async function handleResume() {
started.value = true
applyQteParams()
await resumeAutoSave()
}
function applyQteParams() {
engine.qteSystem.timeLimitMultiplier = store.qteTimeRelax ? 1.5 : 1
engine.qteSystem.singleKeyMode = store.qteSingleKey
}
function onVideoReady(elA: HTMLVideoElement, elB: HTMLVideoElement) {
videoElA.value = elA
videoElB.value = elB
@@ -117,12 +126,24 @@ watch(() => store.currentScene?.id, async (newId) => {
function onGlobalKeydown(e: KeyboardEvent) {
const key = e.key
if (key === ' ' && store.pauseEnabled && started.value && !store.gameEnded) {
const activeEl = document.activeElement
if (!activeEl || activeEl.tagName === 'BODY' || activeEl === document.body) {
e.preventDefault()
togglePause()
return
}
}
if (key === 'ArrowDown' || key === 'ArrowUp' || key === 'ArrowLeft' || key === 'ArrowRight' ||
key === 'Enter' || key === ' ' || key === 'Tab' || key === 'w' || key === 'a' || key === 's' || key === 'd') {
store.setInputMode('keyboard')
}
if (key === 'Escape') {
if (showChapterSelect.value) {
if (store.showSettings) {
store.showSettings = false
} else if (showChapterSelect.value) {
showChapterSelect.value = false
} else if (showMenu.value) {
showMenu.value = false
@@ -133,6 +154,17 @@ function onGlobalKeydown(e: KeyboardEvent) {
}
}
function togglePause() {
if (!started.value || store.gameEnded) return
if (paused.value) {
paused.value = false
engine.videoManager.getActiveVideoElement()?.play().catch(() => {})
} else {
paused.value = true
engine.videoManager.getActiveVideoElement()?.pause()
}
}
function onGlobalMouseMove() {
store.setInputMode('mouse')
}
@@ -199,6 +231,7 @@ init()
{{ isFullscreen ? '⛶' : '⛶' }}
</button>
<button class="top-btn" @click="toggleMenu">{{ t('ui.menu') }}</button>
<button class="top-btn" @click="store.setShowSettings(true)">设置</button>
</div>
</div>
<div v-if="!started" class="start-overlay">
@@ -208,6 +241,7 @@ init()
<button v-if="store.chapters.length > 0" class="start-btn chapters-btn" @click="openChapterSelect">{{ t('ui.chapters') }}</button>
<button v-if="store.achievementDefs.length > 0" class="start-btn achievement-btn" @click="showAchievements = true">成就</button>
<button v-if="store.endings.length > 0" class="start-btn gallery-btn" @click="showEndingGallery = true">画廊</button>
<button class="start-btn settings-btn" @click="store.setShowSettings(true)">设置</button>
</div>
<div v-if="store.gameEnded" class="game-end-overlay">
<div class="game-end-text">{{ t('ui.gameEnd') }}</div>
@@ -249,6 +283,14 @@ init()
:visited-ids="store.visitedSceneIds"
@close="recapChapterId = null"
/>
<AccessibilitySettings
v-if="store.showSettings"
@close="store.setShowSettings(false)"
/>
<div v-if="paused" class="pause-overlay" @click="togglePause">
<div class="pause-text">已暂停</div>
<div class="pause-hint">点击或按 Space 继续</div>
</div>
<AchievementToast
:achievement-id="store.toastAchievementId"
:definitions="store.achievementDefs"
@@ -390,6 +432,35 @@ html, body {
color: #ce93d8;
}
.settings-btn {
border-color: rgba(255, 255, 255, 0.3);
color: #aaa;
}
.pause-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.75);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 150;
cursor: pointer;
}
.pause-text {
font-size: 36px;
color: #fff;
letter-spacing: 4px;
margin-bottom: 12px;
}
.pause-hint {
font-size: 14px;
color: #888;
}
.game-end-actions {
margin-top: 24px;
display: flex;