feat: engine improvements, new scenes, videos, subtitles, hotspot component and docs update
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { SceneNode, Choice, EngineEvent } from '../types'
|
||||
import type { SceneNode, Choice, EngineEvent, Hotspot } from '../types'
|
||||
import { SceneManager } from './SceneManager'
|
||||
import { VideoManager } from './VideoManager'
|
||||
import { StateManager } from './StateManager'
|
||||
@@ -60,6 +60,16 @@ export class Engine {
|
||||
this.stateManager.apply(scene.onEnter)
|
||||
}
|
||||
|
||||
if (scene.type === 'image') {
|
||||
this.isInitialScene = false
|
||||
this.emit('sceneChange', scene)
|
||||
const visible = this.getVisibleHotspots(scene)
|
||||
if (visible.length > 0) {
|
||||
this.emit('hotspotRequest', visible)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const preloadUrls = this.sceneManager.getCandidateUrls(
|
||||
scene,
|
||||
(conds) => conds ? this.stateManager.evaluate(conds) : true
|
||||
@@ -84,7 +94,11 @@ export class Engine {
|
||||
|
||||
private checkQTE = (time: number) => {
|
||||
const scene = this.currentScene
|
||||
if (!scene?.qte || this.qteTriggered) return
|
||||
if (!scene) return
|
||||
|
||||
this.checkHotspotTime(scene, time)
|
||||
|
||||
if (!scene.qte || this.qteTriggered) return
|
||||
if (time >= scene.qte.triggerTime) {
|
||||
this.qteTriggered = true
|
||||
const qte = scene.qte
|
||||
@@ -126,6 +140,48 @@ export class Engine {
|
||||
}
|
||||
}
|
||||
|
||||
private checkHotspotTime(scene: SceneNode, time: number) {
|
||||
if (!scene.hotspots || scene.hotspots.length === 0) return
|
||||
|
||||
const visible = scene.hotspots.filter((hs) => {
|
||||
if (hs.conditions && !this.stateManager.evaluate(hs.conditions)) return false
|
||||
if (hs.showAt !== undefined && time < hs.showAt) return false
|
||||
if (hs.hideAt !== undefined && time >= hs.hideAt) return false
|
||||
return true
|
||||
})
|
||||
|
||||
this.emit('hotspotUpdate', visible)
|
||||
}
|
||||
|
||||
getVisibleHotspots(scene: SceneNode): Hotspot[] {
|
||||
if (!scene.hotspots) return []
|
||||
return scene.hotspots.filter((hs) => {
|
||||
if (hs.conditions && !this.stateManager.evaluate(hs.conditions)) return false
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
clickHotspot(hotspot: Hotspot) {
|
||||
if (!this.currentScene) return
|
||||
|
||||
if (hotspot.effects) {
|
||||
this.stateManager.apply(hotspot.effects)
|
||||
}
|
||||
|
||||
this.stateManager.recordChoice({
|
||||
sceneId: this.currentScene.id,
|
||||
choiceIndex: -1,
|
||||
choiceText: hotspot.label,
|
||||
})
|
||||
|
||||
const next = this.sceneManager.getScene(hotspot.targetScene)
|
||||
if (next) {
|
||||
this.goToScene(next)
|
||||
} else {
|
||||
this.endGame()
|
||||
}
|
||||
}
|
||||
|
||||
private onVideoEnd(scene: SceneNode) {
|
||||
const validChoices = this.getValidChoices(scene)
|
||||
|
||||
@@ -202,6 +258,15 @@ export class Engine {
|
||||
this.ended = false
|
||||
this.isInitialScene = false
|
||||
|
||||
if (scene.type === 'image') {
|
||||
this.emit('sceneChange', scene)
|
||||
const visible = this.getVisibleHotspots(scene)
|
||||
if (visible.length > 0) {
|
||||
this.emit('hotspotRequest', visible)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const preloadUrls = this.sceneManager.getCandidateUrls(
|
||||
scene,
|
||||
(conds) => conds ? this.stateManager.evaluate(conds) : true
|
||||
|
||||
Reference in New Issue
Block a user