spine资源引入
This commit is contained in:
1 parent
166b5015c2
commit
5f4667f736
25 files changed
+31151
-9082
No files matched your search
@@ -0,0 +1,83 @@
|
||||
import { Container } from 'pixi.js'
|
||||
import { Spine } from '@esotericsoftware/spine-pixi-v7'
|
||||
import { getSpineAsset } from './spineAssetRegistry'
|
||||
import type { SpineSceneObject } from './spineTypes'
|
||||
|
||||
interface RuntimeEntry {
|
||||
root: Container
|
||||
spine: Spine
|
||||
assetVersion: number
|
||||
animation: string
|
||||
}
|
||||
|
||||
export class SpineRuntimeLayer {
|
||||
readonly container = new Container()
|
||||
private entries = new Map<number, RuntimeEntry>()
|
||||
|
||||
sync(objects: SpineSceneObject[], frame: number, fps: number, showResources = true) {
|
||||
for (const [id, entry] of this.entries) {
|
||||
if (objects.some((object) => object.id === id)) continue
|
||||
this.container.removeChild(entry.root)
|
||||
entry.root.destroy({ children: true })
|
||||
this.entries.delete(id)
|
||||
}
|
||||
|
||||
for (const object of objects) {
|
||||
const asset = getSpineAsset(object.id)
|
||||
let entry = this.entries.get(object.id)
|
||||
if (entry && entry.assetVersion !== object.assetVersion && !asset) {
|
||||
this.container.removeChild(entry.root)
|
||||
entry.root.destroy({ children: true })
|
||||
this.entries.delete(object.id)
|
||||
entry = undefined
|
||||
}
|
||||
if ((!entry || entry.assetVersion !== object.assetVersion) && asset) {
|
||||
if (entry) {
|
||||
this.container.removeChild(entry.root)
|
||||
entry.root.destroy({ children: true })
|
||||
}
|
||||
const root = new Container()
|
||||
const spine = new Spine({ skeletonData: asset.skeletonData, autoUpdate: false, darkTint: false })
|
||||
root.addChild(spine)
|
||||
this.container.addChild(root)
|
||||
entry = { root, spine, assetVersion: object.assetVersion, animation: '' }
|
||||
this.entries.set(object.id, entry)
|
||||
}
|
||||
if (!entry) continue
|
||||
|
||||
const root = entry.root
|
||||
const spine = entry.spine
|
||||
const visible = showResources && object.enabled
|
||||
root.visible = visible
|
||||
root.renderable = visible
|
||||
root.position.set(object.x, -object.y)
|
||||
root.rotation = -object.rotation * Math.PI / 180
|
||||
root.scale.set(object.scaleX, object.scaleY)
|
||||
|
||||
if (entry.animation !== object.selectedAnimation) {
|
||||
entry.animation = object.selectedAnimation
|
||||
spine.skeleton.setToSetupPose()
|
||||
spine.state.clearTracks()
|
||||
// 编辑器时间轴负责整体循环;单个 Spine 动画自身只播放一次并停在末帧。
|
||||
if (entry.animation) spine.state.setAnimation(0, entry.animation, false)
|
||||
}
|
||||
const track = spine.state.getCurrent(0)
|
||||
if (track) {
|
||||
const duration = object.animations.find((animation) => animation.name === object.selectedAnimation)?.duration || 0
|
||||
const localTime = Math.max(0, frame / Math.max(1, fps) - object.timeOffset)
|
||||
track.trackTime = duration > 0 ? Math.min(localTime, duration) : localTime
|
||||
}
|
||||
spine.update(0)
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
for (const entry of this.entries.values()) {
|
||||
entry.root.removeFromParent()
|
||||
entry.root.destroy({ children: true })
|
||||
}
|
||||
this.entries.clear()
|
||||
this.container.removeFromParent()
|
||||
this.container.destroy({ children: true })
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user