骨架改为显示spine

This commit is contained in:
tianmo
2026-08-29 03:36:21 +08:00
parent 031359586d
commit 7aa8748cca
4 changed files with 11 additions and 12 deletions
+6 -6
View File
@@ -1,7 +1,7 @@
<template>
<div class="spine-editor">
<div class="editor-title">骨架属性</div>
<label class="field wide"><span>骨架名称</span><input v-model="spineObject.name" /></label>
<div class="editor-title">Spine 属性</div>
<label class="field wide"><span>Spine 名称</span><input v-model="spineObject.name" /></label>
<div class="grid three">
<label class="field"><span>X 位置</span><input v-model.number="spineObject.x" type="number" /></label>
<label class="field"><span>Y 位置</span><input v-model.number="spineObject.y" type="number" /></label>
@@ -13,7 +13,7 @@
<label class="field"><span>开始时间</span><input v-model.number="spineObject.timeOffset" type="number" min="0" step="0.033333" @change="recalcTimeline" /></label>
</div>
<div class="divider"></div>
<div class="section-title">骨架资源</div>
<div class="section-title">Spine 资源</div>
<input ref="skeletonInput" hidden type="file" accept=".json,.skel,application/json,application/octet-stream" @change="selectSkeleton" />
<input ref="atlasInput" hidden type="file" accept=".atlas,text/plain" @change="selectAtlas" />
<input ref="textureInput" hidden type="file" multiple accept=".png,.jpg,.jpeg,.webp,.wepb,image/png,image/jpeg,image/webp" @change="selectTextures" />
@@ -39,7 +39,7 @@
<div v-if="spineObject.error" class="error">{{ spineObject.error }}</div>
<div class="section-box">
<div class="section-title">骨架动画</div>
<div class="section-title">Spine 动画</div>
<div v-if="!spineObject.animations.length" class="empty">无可用动画</div>
<label v-else class="field wide">
<span>时间轴播放动画</span>
@@ -57,7 +57,7 @@
<div class="section-title">层级树</div>
<button v-if="spineObject.bones.length" class="tree-action" @click="toggleAllBones">{{ allBonesCollapsed ? '全部展开' : '全部折叠' }}</button>
</div>
<div v-if="!spineObject.bones.length" class="empty">未加载骨架</div>
<div v-if="!spineObject.bones.length" class="empty">未加载 Spine</div>
<div v-else class="bone-tree">
<div v-for="bone in visibleBones" :key="bone.name" class="bone" :style="{ paddingLeft: `${6 + bone.depth * 16}px` }">
<button
@@ -137,7 +137,7 @@ async function loadBundle() {
const atlas = atlasFile.value
if (!skeleton || !atlas || !textureFiles.value.length) {
props.spineObject.status = 'error'
props.spineObject.error = '请依次选择骨架数据、Atlas 和全部纹理图片'
props.spineObject.error = '请依次选择 Spine 数据、Atlas 和全部纹理图片'
return
}
props.spineObject.status = 'loading'
+1 -2
View File
@@ -39,7 +39,7 @@ function boneMetadata(skeletonData: SkeletonData): SpineBoneInfo[] {
}
export async function parseSpineBundle(skeletonFile: File, atlasFile: File, textureFiles: File[]): Promise<ParsedSpineBundle> {
if (!/\.(json|skel)$/i.test(skeletonFile.name)) throw new Error('骨架数据仅支持 .json 或 .skel')
if (!/\.(json|skel)$/i.test(skeletonFile.name)) throw new Error('Spine 数据仅支持 .json 或 .skel')
if (!/\.atlas$/i.test(atlasFile.name)) throw new Error('图集文件仅支持 .atlas')
if (!textureFiles.length) throw new Error('请至少选择一张纹理图片')
@@ -76,4 +76,3 @@ export async function parseSpineBundle(skeletonFile: File, atlasFile: File, text
throw error
}
}
+3 -3
View File
@@ -12,7 +12,7 @@
<button class="scene-add" title="添加粒子系统" @click.stop="addSys">粒子</button>
<button class="scene-add" title="添加碰撞体" @click.stop="addCollider">碰撞</button>
<button class="scene-add" title="添加路径" @click.stop="addPath">路径</button>
<button class="scene-add" title="添加 Spine 骨架" @click.stop="addSpine">骨架</button>
<button class="scene-add" title="添加 Spine" @click.stop="addSpine">Spine</button>
</div>
</div>
<div class="group-body" v-show="!collapsed.scene">
@@ -62,8 +62,8 @@
>
<span class="tdot spine-dot"></span>
<span class="tlabel">{{ spine.name }}</span>
<span class="scene-object-kind">骨架</span>
<button class="scene-object-delete" title="删除骨架" @click.stop="store.removeSpine(spine.id)"></button>
<span class="scene-object-kind">Spine</span>
<button class="scene-object-delete" title="删除 Spine" @click.stop="store.removeSpine(spine.id)"></button>
</div>
<div v-if="!store.systems.length && !store.colliders.length && !store.paths.length && !store.spines.length" class="empty">场景中暂无对象</div>
</div>
+1 -1
View File
@@ -11,7 +11,7 @@
<button class="tl-btn" @click="store.toEnd()" title="移动到最后一帧"></button>
<button class="tl-btn" :class="{ on: store.timeline.loop }" @click="store.toggleLoop()" title="循环"></button>
<span class="tl-frame"> {{ store.timeline.frame }} / {{ store.timeline.totalFrames }}</span>
<span class="tl-legend"><i class="legend-emission"></i>持续发射 <i class="legend-life"></i>粒子存在 <i class="legend-spine"></i>骨架动画</span>
<span class="tl-legend"><i class="legend-emission"></i>持续发射 <i class="legend-life"></i>粒子存在 <i class="legend-spine"></i>Spine 动画</span>
<label class="tl-anim">动画
<select v-model="store.timeline.animation" class="tl-sel">
<option value="animation">animation</option>