feat: press Esc to open menu during gameplay, close with Esc
This commit is contained in:
32
src/App.vue
32
src/App.vue
@@ -8,11 +8,14 @@ import HotspotLayer from '@/components/HotspotLayer.vue'
|
|||||||
import SaveLoadMenu from '@/components/SaveLoadMenu.vue'
|
import SaveLoadMenu from '@/components/SaveLoadMenu.vue'
|
||||||
import ChapterSelect from '@/components/ChapterSelect.vue'
|
import ChapterSelect from '@/components/ChapterSelect.vue'
|
||||||
import PlaybackBar from '@/components/PlaybackBar.vue'
|
import PlaybackBar from '@/components/PlaybackBar.vue'
|
||||||
|
import LangSwitch from '@/components/LangSwitch.vue'
|
||||||
import { useGameEngine } from '@/composables/useGameEngine'
|
import { useGameEngine } from '@/composables/useGameEngine'
|
||||||
import { useGameStore } from '@/stores/gameStore'
|
import { useGameStore } from '@/stores/gameStore'
|
||||||
import { useFullscreen } from '@/composables/useFullscreen'
|
import { useFullscreen } from '@/composables/useFullscreen'
|
||||||
|
import { useI18n } from '@/composables/useI18n'
|
||||||
|
|
||||||
const store = useGameStore()
|
const store = useGameStore()
|
||||||
|
const { t, currentLang } = useI18n()
|
||||||
const { isFullscreen, toggle: toggleFullscreen } = useFullscreen()
|
const { isFullscreen, toggle: toggleFullscreen } = useFullscreen()
|
||||||
const videoElA = ref<HTMLVideoElement | null>(null)
|
const videoElA = ref<HTMLVideoElement | null>(null)
|
||||||
const videoElB = ref<HTMLVideoElement | null>(null)
|
const videoElB = ref<HTMLVideoElement | null>(null)
|
||||||
@@ -108,6 +111,9 @@ function onGlobalKeydown(e: KeyboardEvent) {
|
|||||||
showChapterSelect.value = false
|
showChapterSelect.value = false
|
||||||
} else if (showMenu.value) {
|
} else if (showMenu.value) {
|
||||||
showMenu.value = false
|
showMenu.value = false
|
||||||
|
} else if (started.value && !store.gameEnded) {
|
||||||
|
showMenu.value = true
|
||||||
|
refreshSaves()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,8 +122,6 @@ function onGlobalMouseMove() {
|
|||||||
store.setInputMode('mouse')
|
store.setInputMode('mouse')
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyboardKeys = ['ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight', 'Enter', 'Tab', ' ', 'w', 'a', 's', 'd']
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.addEventListener('keydown', onGlobalKeydown)
|
document.addEventListener('keydown', onGlobalKeydown)
|
||||||
document.addEventListener('mousemove', onGlobalMouseMove)
|
document.addEventListener('mousemove', onGlobalMouseMove)
|
||||||
@@ -133,7 +137,7 @@ init()
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<div v-if="loading" class="loading">加载中...</div>
|
<div v-if="loading" class="loading">{{ t('ui.loading') }}</div>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="game-screen">
|
<div class="game-screen">
|
||||||
<GamePlayer v-show="!store.isImageScene" @video-ready="onVideoReady" />
|
<GamePlayer v-show="!store.isImageScene" @video-ready="onVideoReady" />
|
||||||
@@ -146,6 +150,8 @@ init()
|
|||||||
<Subtitles
|
<Subtitles
|
||||||
:current-time="store.videoTime"
|
:current-time="store.videoTime"
|
||||||
:subtitle-url="store.currentScene?.subtitleUrl ?? null"
|
:subtitle-url="store.currentScene?.subtitleUrl ?? null"
|
||||||
|
:subtitles="store.currentScene?.subtitles ?? null"
|
||||||
|
:lang="currentLang"
|
||||||
/>
|
/>
|
||||||
<QTEOverlay
|
<QTEOverlay
|
||||||
:visible="store.qteActive"
|
:visible="store.qteActive"
|
||||||
@@ -169,21 +175,22 @@ init()
|
|||||||
@skip="handleSkip"
|
@skip="handleSkip"
|
||||||
@speed-change="handleSpeedChange"
|
@speed-change="handleSpeedChange"
|
||||||
/>
|
/>
|
||||||
<button class="top-btn" @click="toggleFullscreen" :title="isFullscreen ? '退出全屏' : '全屏'">
|
<button class="top-btn" @click="toggleFullscreen" :title="isFullscreen ? t('ui.exitFullscreen') : t('ui.fullscreen')">
|
||||||
{{ isFullscreen ? '⛶' : '⛶' }}
|
{{ isFullscreen ? '⛶' : '⛶' }}
|
||||||
</button>
|
</button>
|
||||||
<button class="top-btn" @click="toggleMenu">菜单</button>
|
<button class="top-btn" @click="toggleMenu">{{ t('ui.menu') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!started" class="start-overlay">
|
<div v-if="!started" class="start-overlay">
|
||||||
<button class="start-btn" @click="handleStart">开始游戏</button>
|
<LangSwitch />
|
||||||
<button v-if="hasAutoSave" class="start-btn resume-btn" @click="handleResume">继续上次进度</button>
|
<button class="start-btn" @click="handleStart">{{ t('ui.start') }}</button>
|
||||||
<button v-if="store.chapters.length > 0" class="start-btn chapters-btn" @click="openChapterSelect">章节选择</button>
|
<button v-if="hasAutoSave" class="start-btn resume-btn" @click="handleResume">{{ t('ui.resume') }}</button>
|
||||||
|
<button v-if="store.chapters.length > 0" class="start-btn chapters-btn" @click="openChapterSelect">{{ t('ui.chapters') }}</button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="store.gameEnded" class="game-end-overlay">
|
<div v-if="store.gameEnded" class="game-end-overlay">
|
||||||
<div class="game-end-text">游戏结束</div>
|
<div class="game-end-text">{{ t('ui.gameEnd') }}</div>
|
||||||
<div v-if="store.chapters.length > 0" class="game-end-actions">
|
<div v-if="store.chapters.length > 0" class="game-end-actions">
|
||||||
<button class="end-btn" @click="openChapterSelect">章节选择</button>
|
<button class="end-btn" @click="openChapterSelect">{{ t('ui.chapters') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<SaveLoadMenu
|
<SaveLoadMenu
|
||||||
@@ -277,6 +284,7 @@ html, body {
|
|||||||
inset: 0;
|
inset: 0;
|
||||||
background: rgba(0, 0, 0, 0.8);
|
background: rgba(0, 0, 0, 0.8);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
@@ -292,6 +300,7 @@ html, body {
|
|||||||
inset: 0;
|
inset: 0;
|
||||||
background: rgba(0, 0, 0, 0.85);
|
background: rgba(0, 0, 0, 0.85);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
@@ -307,6 +316,7 @@ html, body {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
letter-spacing: 4px;
|
letter-spacing: 4px;
|
||||||
transition: background 0.2s;
|
transition: background 0.2s;
|
||||||
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.start-btn:hover {
|
.start-btn:hover {
|
||||||
@@ -314,13 +324,11 @@ html, body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.resume-btn {
|
.resume-btn {
|
||||||
margin-top: 16px;
|
|
||||||
border-color: rgba(100, 200, 255, 0.3);
|
border-color: rgba(100, 200, 255, 0.3);
|
||||||
color: #8cf;
|
color: #8cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chapters-btn {
|
.chapters-btn {
|
||||||
margin-top: 16px;
|
|
||||||
border-color: rgba(255, 200, 100, 0.3);
|
border-color: rgba(255, 200, 100, 0.3);
|
||||||
color: #fc8;
|
color: #fc8;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user