跳转到内容

Spine 动画

Estella 内置 Spine 骨骼动画:骨骼、网格、IK、皮肤与事件。 它由 SpineAnimation 组件驱动,并在运行时通过 Spine 资源(来自 esengine/spine 子路径) 控制。

在编辑器里添加并指向你的 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: 引用,移动或重命名 文件都不会断链。编辑器在视口里实时预览骨骼——跨越播放/停止也不丢——骨骼加载完成后, animationskin 字段会变成该骨骼实际动画与皮肤的下拉列表。

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 attachment
spine.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 } | null

SpineEvents 资源每帧发布一次轨道事件——在同一帧读取:

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 也能驱动精灵。
  • 动画 —— Animator 状态机可以驱动 Spine。
  • 资源 —— 加载骨骼 + 图集资源。