feat: global assetBase for scene JSON, convert demo to relative paths
This commit is contained in:
@@ -100,6 +100,7 @@ export interface GameData {
|
||||
scenes: Record<string, SceneNode>
|
||||
startScene: string
|
||||
variables: Record<string, number>
|
||||
assetBase?: string
|
||||
chapters?: ChapterInfo[]
|
||||
achievements?: AchievementDef[]
|
||||
endings?: EndingDef[]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"assetBase": "",
|
||||
"startScene": "intro",
|
||||
"variables": {
|
||||
"trust": 50,
|
||||
@@ -32,43 +33,43 @@
|
||||
}
|
||||
],
|
||||
"endings": [
|
||||
{ "id": "trust_end", "label": "信任的伙伴", "sceneId": "trust_ending", "chapterId": "ch1", "thumbnail": "/images/end_trust.jpg" },
|
||||
{ "id": "alone_end", "label": "独行之路", "sceneId": "alone_ending", "chapterId": "ch1", "thumbnail": "/images/end_alone.jpg" },
|
||||
{ "id": "continue_end", "label": "继续前行", "sceneId": "continue_ending", "chapterId": "ch3", "thumbnail": "/images/end_continue.jpg" }
|
||||
{ "id": "trust_end", "label": "信任的伙伴", "sceneId": "trust_ending", "chapterId": "ch1", "thumbnail": "images/end_trust.jpg" },
|
||||
{ "id": "alone_end", "label": "独行之路", "sceneId": "alone_ending", "chapterId": "ch1", "thumbnail": "images/end_alone.jpg" },
|
||||
{ "id": "continue_end", "label": "继续前行", "sceneId": "continue_ending", "chapterId": "ch3", "thumbnail": "images/end_continue.jpg" }
|
||||
],
|
||||
"chapters": [
|
||||
{
|
||||
"id": "ch1",
|
||||
"label": "第一章:醒来",
|
||||
"startScene": "intro",
|
||||
"thumbnail": "/images/ch1.jpg",
|
||||
"thumbnail": "images/ch1.jpg",
|
||||
"defaultVariables": { "trust": 50, "courage": 0, "investigation": 0 }
|
||||
},
|
||||
{
|
||||
"id": "ch2",
|
||||
"label": "第二章:调查",
|
||||
"startScene": "desk_detail",
|
||||
"thumbnail": "/images/ch2.jpg",
|
||||
"thumbnail": "images/ch2.jpg",
|
||||
"defaultVariables": { "trust": 60, "courage": 10, "investigation": 1 }
|
||||
},
|
||||
{
|
||||
"id": "ch3",
|
||||
"label": "第三章:终局",
|
||||
"startScene": "qte_success",
|
||||
"thumbnail": "/images/ch3.jpg",
|
||||
"thumbnail": "images/ch3.jpg",
|
||||
"defaultVariables": { "trust": 70, "courage": 20, "investigation": 2 }
|
||||
}
|
||||
],
|
||||
"scenes": {
|
||||
"intro": {
|
||||
"id": "intro",
|
||||
"videoUrl": "/videos/intro.mp4",
|
||||
"subtitleUrl": "/subtitles/intro.vtt",
|
||||
"videoUrl": "videos/intro.mp4",
|
||||
"subtitleUrl": "subtitles/intro.vtt",
|
||||
"subtitles": {
|
||||
"zh": "/subtitles/intro.vtt",
|
||||
"en": "/subtitles/intro_en.vtt"
|
||||
"zh": "subtitles/intro.vtt",
|
||||
"en": "subtitles/intro_en.vtt"
|
||||
},
|
||||
"bgmUrl": "/audio/calm_bgm.mp3",
|
||||
"bgmUrl": "audio/calm_bgm.mp3",
|
||||
"bgmVolume": 0.6,
|
||||
"bgmCrossFade": 1.5,
|
||||
"videoMuted": true,
|
||||
@@ -105,8 +106,8 @@
|
||||
"id": "investigation_site",
|
||||
"type": "image",
|
||||
"videoUrl": "",
|
||||
"imageUrl": "/images/investigation_scene.jpg",
|
||||
"subtitleUrl": "/subtitles/investigation.vtt",
|
||||
"imageUrl": "images/investigation_scene.jpg",
|
||||
"subtitleUrl": "subtitles/investigation.vtt",
|
||||
"hotspots": [
|
||||
{
|
||||
"id": "hs_desk",
|
||||
@@ -142,7 +143,7 @@
|
||||
},
|
||||
"corridor": {
|
||||
"id": "corridor",
|
||||
"videoUrl": "/videos/corridor.mp4",
|
||||
"videoUrl": "videos/corridor.mp4",
|
||||
"hotspots": [
|
||||
{
|
||||
"id": "hs_left",
|
||||
@@ -172,8 +173,8 @@
|
||||
},
|
||||
"left_door": {
|
||||
"id": "left_door",
|
||||
"videoUrl": "/videos/left_door.mp4",
|
||||
"subtitleUrl": "/subtitles/left_door.vtt",
|
||||
"videoUrl": "videos/left_door.mp4",
|
||||
"subtitleUrl": "subtitles/left_door.vtt",
|
||||
"choices": [
|
||||
{
|
||||
"text": "与陌生人握手",
|
||||
@@ -192,9 +193,9 @@
|
||||
},
|
||||
"right_door": {
|
||||
"id": "right_door",
|
||||
"videoUrl": "/videos/right_door.mp4",
|
||||
"videoUrl": "videos/right_door.mp4",
|
||||
"skippable": false,
|
||||
"bgmUrl": "/audio/tense_bgm.mp3",
|
||||
"bgmUrl": "audio/tense_bgm.mp3",
|
||||
"bgmVolume": 0.7,
|
||||
"bgmCrossFade": 2.0,
|
||||
"videoMuted": true,
|
||||
@@ -216,7 +217,7 @@
|
||||
},
|
||||
"qte_success": {
|
||||
"id": "qte_success",
|
||||
"videoUrl": "/videos/qte_success.mp4",
|
||||
"videoUrl": "videos/qte_success.mp4",
|
||||
"choices": [
|
||||
{
|
||||
"text": "继续前进",
|
||||
@@ -230,7 +231,7 @@
|
||||
},
|
||||
"qte_fail": {
|
||||
"id": "qte_fail",
|
||||
"videoUrl": "/videos/qte_fail.mp4",
|
||||
"videoUrl": "videos/qte_fail.mp4",
|
||||
"choices": [
|
||||
{
|
||||
"text": "继续前进",
|
||||
@@ -244,7 +245,7 @@
|
||||
},
|
||||
"desk_detail": {
|
||||
"id": "desk_detail",
|
||||
"videoUrl": "/videos/continue_ending.mp4",
|
||||
"videoUrl": "videos/continue_ending.mp4",
|
||||
"choices": [
|
||||
{
|
||||
"text": "返回调查现场",
|
||||
@@ -258,9 +259,9 @@
|
||||
},
|
||||
"stay": {
|
||||
"id": "stay",
|
||||
"videoUrl": "/videos/stay_loop.mp4",
|
||||
"subtitleUrl": "/subtitles/stay.vtt",
|
||||
"bgmUrl": "/audio/calm_bgm.mp3",
|
||||
"videoUrl": "videos/stay_loop.mp4",
|
||||
"subtitleUrl": "subtitles/stay.vtt",
|
||||
"bgmUrl": "audio/calm_bgm.mp3",
|
||||
"bgmVolume": 0.6,
|
||||
"videoMuted": true,
|
||||
"loopStart": 3.0,
|
||||
@@ -271,7 +272,7 @@
|
||||
},
|
||||
"trust_ending": {
|
||||
"id": "trust_ending",
|
||||
"videoUrl": "/videos/trust_ending.mp4",
|
||||
"videoUrl": "videos/trust_ending.mp4",
|
||||
"choices": [
|
||||
{
|
||||
"text": "开启信任的旅程(需要 trust >= 80)",
|
||||
@@ -290,12 +291,12 @@
|
||||
},
|
||||
"secret_ending": {
|
||||
"id": "secret_ending",
|
||||
"videoUrl": "/videos/continue_ending.mp4",
|
||||
"videoUrl": "videos/continue_ending.mp4",
|
||||
"choices": []
|
||||
},
|
||||
"alone_ending": {
|
||||
"id": "alone_ending",
|
||||
"videoUrl": "/videos/alone_ending.mp4",
|
||||
"videoUrl": "videos/alone_ending.mp4",
|
||||
"choices": [],
|
||||
"onEnter": [
|
||||
{ "type": "set", "target": "completed_game", "value": 1 }
|
||||
@@ -303,7 +304,7 @@
|
||||
},
|
||||
"continue_ending": {
|
||||
"id": "continue_ending",
|
||||
"videoUrl": "/videos/continue_ending.mp4",
|
||||
"videoUrl": "videos/continue_ending.mp4",
|
||||
"choices": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,9 +111,43 @@ export function useGameEngine(videoEls: () => [HTMLVideoElement | null, HTMLVide
|
||||
store.setVideoTime(t)
|
||||
})
|
||||
|
||||
function resolveAsset(base: string, path: string): string {
|
||||
if (!path || path.startsWith('http://') || path.startsWith('https://') || path.startsWith('data:')) return path
|
||||
const b = base.endsWith('/') ? base.slice(0, -1) : base
|
||||
const p = path.startsWith('/') ? path : '/' + path
|
||||
return b + p
|
||||
}
|
||||
|
||||
function applyAssetBase(data: GameData) {
|
||||
const base = data.assetBase || ''
|
||||
if (!base) return
|
||||
for (const scene of Object.values(data.scenes)) {
|
||||
if (scene.videoUrl) scene.videoUrl = resolveAsset(base, scene.videoUrl)
|
||||
if (scene.subtitleUrl) scene.subtitleUrl = resolveAsset(base, scene.subtitleUrl)
|
||||
if (scene.imageUrl) scene.imageUrl = resolveAsset(base, scene.imageUrl)
|
||||
if (scene.bgmUrl) scene.bgmUrl = resolveAsset(base, scene.bgmUrl)
|
||||
if (scene.subtitles) {
|
||||
for (const k of Object.keys(scene.subtitles)) {
|
||||
scene.subtitles[k] = resolveAsset(base, scene.subtitles[k])
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.endings) {
|
||||
for (const e of data.endings) {
|
||||
if (e.thumbnail) e.thumbnail = resolveAsset(base, e.thumbnail)
|
||||
}
|
||||
}
|
||||
if (data.chapters) {
|
||||
for (const c of data.chapters) {
|
||||
if (c.thumbnail) c.thumbnail = resolveAsset(base, c.thumbnail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function loadGame(dataUrl: string) {
|
||||
const resp = await fetch(dataUrl)
|
||||
const data: GameData = await resp.json()
|
||||
applyAssetBase(data)
|
||||
engine.sceneManager.load(data)
|
||||
engine.stateManager.init(data.variables)
|
||||
store.setChapters(data.chapters || [])
|
||||
|
||||
Reference in New Issue
Block a user