feat: chapter select system, multi-chapter support, scene manager refactor, and docs update
This commit is contained in:
56
src/App.vue
56
src/App.vue
@@ -6,6 +6,7 @@ import QTEOverlay from '@/components/QTEOverlay.vue'
|
||||
import Subtitles from '@/components/Subtitles.vue'
|
||||
import HotspotLayer from '@/components/HotspotLayer.vue'
|
||||
import SaveLoadMenu from '@/components/SaveLoadMenu.vue'
|
||||
import ChapterSelect from '@/components/ChapterSelect.vue'
|
||||
import { useGameEngine } from '@/composables/useGameEngine'
|
||||
import { useGameStore } from '@/stores/gameStore'
|
||||
import { useFullscreen } from '@/composables/useFullscreen'
|
||||
@@ -17,9 +18,11 @@ const videoElB = ref<HTMLVideoElement | null>(null)
|
||||
const loading = ref(true)
|
||||
const started = ref(false)
|
||||
const showMenu = ref(false)
|
||||
const showChapterSelect = ref(false)
|
||||
const hasAutoSave = ref(false)
|
||||
|
||||
const { loadGame, start, resumeAutoSave, makeChoice, clickHotspot, saveGame, loadGameFromSlot, refreshSaves, saveSystem } =
|
||||
const { loadGame, start, resumeAutoSave, makeChoice, clickHotspot, startChapter,
|
||||
saveGame, loadGameFromSlot, refreshSaves, saveSystem } =
|
||||
useGameEngine(() => [videoElA.value, videoElB.value])
|
||||
|
||||
async function init() {
|
||||
@@ -63,6 +66,17 @@ async function onLoad(slot: number) {
|
||||
showMenu.value = false
|
||||
}
|
||||
|
||||
function openChapterSelect() {
|
||||
showMenu.value = false
|
||||
showChapterSelect.value = true
|
||||
}
|
||||
|
||||
async function onStartChapter(chapterId: string) {
|
||||
showChapterSelect.value = false
|
||||
started.value = true
|
||||
startChapter(chapterId)
|
||||
}
|
||||
|
||||
init()
|
||||
</script>
|
||||
|
||||
@@ -107,9 +121,13 @@ init()
|
||||
<div v-if="!started" class="start-overlay">
|
||||
<button class="start-btn" @click="handleStart">开始游戏</button>
|
||||
<button v-if="hasAutoSave" class="start-btn resume-btn" @click="handleResume">继续上次进度</button>
|
||||
<button v-if="store.chapters.length > 0" class="start-btn chapters-btn" @click="openChapterSelect">章节选择</button>
|
||||
</div>
|
||||
<div v-if="store.gameEnded" class="game-end-overlay">
|
||||
<div class="game-end-text">游戏结束</div>
|
||||
<div v-if="store.chapters.length > 0" class="game-end-actions">
|
||||
<button class="end-btn" @click="openChapterSelect">章节选择</button>
|
||||
</div>
|
||||
</div>
|
||||
<SaveLoadMenu
|
||||
v-if="showMenu"
|
||||
@@ -118,6 +136,13 @@ init()
|
||||
@load="onLoad"
|
||||
@close="showMenu = false"
|
||||
/>
|
||||
<ChapterSelect
|
||||
v-if="showChapterSelect"
|
||||
:chapters="store.chapters"
|
||||
:unlocked-ids="store.unlockedChapterIds"
|
||||
@select="onStartChapter"
|
||||
@back="showChapterSelect = false"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
@@ -236,4 +261,33 @@ html, body {
|
||||
border-color: rgba(100, 200, 255, 0.3);
|
||||
color: #8cf;
|
||||
}
|
||||
|
||||
.chapters-btn {
|
||||
margin-top: 16px;
|
||||
border-color: rgba(255, 200, 100, 0.3);
|
||||
color: #fc8;
|
||||
}
|
||||
|
||||
.game-end-actions {
|
||||
margin-top: 24px;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.end-btn {
|
||||
padding: 14px 32px;
|
||||
font-size: 18px;
|
||||
color: #fc8;
|
||||
background: rgba(255, 200, 100, 0.08);
|
||||
border: 1px solid rgba(255, 200, 100, 0.2);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
letter-spacing: 2px;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.end-btn:hover {
|
||||
background: rgba(255, 200, 100, 0.15);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user