Spine 动画
Estella 内置 Spine 骨骼动画:骨骼、网格、IK、皮肤与事件。
它由 SpineAnimation 组件驱动,并在运行时通过 Spine 资源(来自 esengine/spine 子路径)
控制。
SpineAnimation 组件
Section titled “SpineAnimation 组件”在编辑器里添加并指向你的 Spine 资源。组件本身在主 esengine 包里。
| 属性 | 类型 | 默认 | 说明 |
|---|---|---|---|
skeletonPath |
asset | '' |
骨骼文件(.json / .skel)。 |
atlasPath |
asset | '' |
图集文件。 |
skin |
string | '' |
活动皮肤(空 = 默认)。 |
animation |
string | '' |
轨道 0 上的初始动画。 |
loop |
boolean | true |
循环初始动画。 |
playing |
boolean | true |
播放是否推进。 |
timeScale |
number | 1 |
逐实体的播放速度。 |
skeletonScale |
number | 1 |
骨骼统一缩放。 |
flipX / flipY |
boolean | false |
水平 / 垂直镜像。 |
color |
Color | {1,1,1,1} |
着色(RGBA,0..1)。 |
layer |
number | 0 |
决定绘制顺序的排序层。 |
material |
asset | 无 | 可选的自定义材质。 |
enabled |
boolean | true |
关掉即冻结并隐藏。 |
骨骼与图集是 Details 面板里的资产槽位:从弹出选择器里挑,从内容浏览器拖进来,
或用槽位的定位 / 清除操作。场景把它们序列化为可移植的 @uuid: 引用,移动或重命名
文件都不会断链。编辑器在视口里实时预览骨骼——跨越播放/停止也不丢——骨骼加载完成后,
animation 和 skin 字段会变成该骨骼实际动画与皮肤的下拉列表。
Spine 导出的 .atlas 文件即用即好——包括多页图集(每页纹理随图集一起加载)和
预乘 alpha:图集头里的 pma: true 自动生效,无需导入设置。导出时开启压缩纹理,
图集页会烘焙成 KTX2,并像其他纹理一样在设备上转码。
Spine 资源控制轨道、混合(crossfade)与逐轨道混合:
import { defineSystem, Query, Res, SpineAnimation } from 'esengine';import { Spine } from 'esengine/spine';
const control = defineSystem([Query(SpineAnimation), Res(Spine)], (q, spine) => { for (const [entity] of q) { spine.setAnimation(entity, 'run', true); // play on track 0, looped spine.setDefaultMix(entity, 0.15); // default crossfade spine.setMixDuration(entity, 'idle', 'run', 0.25); // specific transition spine.setTrackAlpha(entity, 0, 1.0); // blend a track in/out }});| 方法 | 说明 |
|---|---|
setAnimation(entity, name, loop) |
在轨道 0 播放一个动画。 |
setDefaultMix(entity, seconds) |
任意两个动画之间的默认交叉淡入。 |
setMixDuration(entity, from, to, seconds) |
特定转移的交叉淡入。 |
setTrackAlpha(entity, track, alpha) |
混合某轨道的贡献(0..1)。 |
setEntityProps(entity, props) |
一次性设置 { skeletonScale?, flipX?, flipY?, layer? }。 |
setIKTarget(entity, constraint, x, y, mix) |
让 IK 约束对准一个世界坐标点(mix 0..1)。 |
变换 / 路径约束的混合也可调——listConstraints(entity)、getTransformConstraintMix /
setTransformConstraintMix,以及 path 对应项。
spine.setSkin(entity, 'armored');spine.setAttachment(entity, 'weapon-slot', 'sword'); // swap a slot's attachmentspine.setSlotColor(entity, 'body', 1, 0.5, 0.5, 1); // r, g, b, a (0..1)| 方法 | 说明 |
|---|---|
setSkin(entity, name) |
切换活动皮肤。 |
setAttachment(entity, slot, attachment) |
替换某槽位的附件(换装/变体)。 |
setSlotColor(entity, slot, r, g, b, a) |
给单个槽位着色(四个 0..1 通道)。 |
const anims = spine.getAnimations(entity); // string[]const skins = spine.getSkins(entity); // string[]const bounds = spine.getBounds(entity); // { x, y, width, height } | nullSpineEvents 资源每帧发布一次轨道事件——在同一帧读取:
import { defineSystem, Res } from 'esengine';import { SpineEvents } from 'esengine/spine';
const onSpine = defineSystem([Res(SpineEvents)], (spineEvents) => { for (const e of spineEvents.events) { // e.type: 'start' | 'interrupt' | 'end' | 'complete' | 'event' // e.entity, e.track, e.animationName; for 'event': e.eventName + values }});事件 type |
触发时机 |
|---|---|
start |
某轨道上开始一个动画。 |
interrupt |
一个动画被另一个打断。 |
end |
一个动画从轨道移除。 |
complete |
一个动画循环/播放完成。 |
event |
用户编辑的事件关键帧触发(eventName + 值)。 |
- 设一个默认混合(
setDefaultMix)让转移交叉淡入而非硬切;热点路径用setMixDuration覆盖。 - 用轨道 +
setTrackAlpha分层(例如在轨道 1 放一个瞄准/叠加,混合在轨道 0 的移动之上)。 - 跨实体共享骨骼 + 图集——它们引用计数同一份已加载骨骼。
- 用 Animator 状态机驱动整个角色,它既能驱动 Spine 也能驱动精灵。