跳转到内容

Spine 动画

SpineAnimation 组件播放 Spine 骨骼动画。在场景编辑器中将它和 Transform 一起添加到实体上。

属性

属性类型默认值说明
skeletonPathstring''骨骼 JSON 文件路径
atlasPathstring''图集文件路径
skinstring''当前皮肤名
animationstring''当前动画名
timeScalenumber1.0播放速度倍率
loopbooleantrue是否循环
playingbooleantrue是否正在播放
flipXbooleanfalse水平翻转
flipYbooleanfalse垂直翻转
colorColor{r:1, g:1, b:1, a:1}着色 RGBA
layernumber0渲染顺序
skeletonScalenumber1.0骨骼缩放因子
materialnumber0材质 ID
enabledbooleantrue是否渲染骨骼动画

设置步骤

  1. 将 Spine 导出文件(.json + .atlas + 图片)放到项目的 assets/ 文件夹
  2. 在场景编辑器中:创建实体 → 添加 TransformSpineAnimation
  3. 设置 skeletonPathatlasPath 指向 Spine 文件
  4. 设置 animation 为要播放的动画名

控制动画

在系统中查询 SpineAnimation 组件来运行时切换动画:

import { defineSystem, addSystem, Res, Input, Query, Mut, SpineAnimation } from 'esengine';
import { Player } from './components';
addSystem(defineSystem(
[Res(Input), Query(Mut(SpineAnimation), Player)],
(input, query) => {
for (const [entity, spine] of query) {
if (input.isKeyPressed('Space')) {
spine.animation = 'jump';
spine.loop = false;
} else if (input.isKeyDown('KeyD') || input.isKeyDown('KeyA')) {
spine.animation = 'run';
spine.loop = true;
} else {
spine.animation = 'idle';
spine.loop = true;
}
}
}
));

皮肤

切换皮肤改变角色外观:

spine.skin = 'warrior';

播放控制

spine.playing = false; // 暂停
spine.playing = true; // 恢复
spine.timeScale = 2.0; // 两倍速
spine.timeScale = 0.5; // 半速

翻转

spine.flipX = true; // 面朝左
spine.flipX = false; // 面朝右(默认)

颜色着色

spine.color = { r: 1, g: 0, b: 0, a: 1 }; // 红色
spine.color = { r: 1, g: 1, b: 1, a: 0.5 }; // 50% 透明

示例:角色控制器

定义 CharacterState 组件,在编辑器中与 SpineAnimation 一起挂载到实体上:

import {
defineComponent, defineSystem, addSystem,
Res, Input, Time, Query, Mut, Transform, SpineAnimation
} from 'esengine';
const CharacterState = defineComponent('CharacterState', {
speed: 200,
currentAnim: 'idle'
});
addSystem(defineSystem(
[Res(Input), Res(Time), Query(Mut(Transform), Mut(SpineAnimation), Mut(CharacterState))],
(input, time, query) => {
for (const [entity, transform, spine, state] of query) {
let moving = false;
if (input.isKeyDown('KeyD')) {
transform.position.x += state.speed * time.delta;
spine.flipX = false;
moving = true;
}
if (input.isKeyDown('KeyA')) {
transform.position.x -= state.speed * time.delta;
spine.flipX = true;
moving = true;
}
const newAnim = moving ? 'run' : 'idle';
if (state.currentAnim !== newAnim) {
state.currentAnim = newAnim;
spine.animation = newAnim;
spine.loop = true;
}
}
}
));

多版本架构

Estella 同时支持 Spine 3.84.14.2 版本。引擎会自动从骨骼数据中检测 Spine 版本并选择对应的运行时后端。

import type { SpineVersion } from 'esengine';
// SpineVersion = '3.8' | '4.1' | '4.2'

工作原理

  • 加载 Spine 资源时,引擎从骨骼文件头中检测版本
  • 自动选择匹配的后端:C++ native(优先)或 WASM fallback
  • 无需修改代码——同一个 SpineAnimation 组件适用于所有版本

SpineManager 运行时 API

对于高级用例,SpineManager 提供运行时查询能力:

import { SpineManager } from 'esengine';
// 从原始数据检测版本(加载前)
const version = SpineManager.detectVersion(skelBinaryData);
const versionJson = SpineManager.detectVersionJson(skelJsonString);
// 查询已加载实体
const manager = app.getResource(SpineManager);
const ver = manager.getEntityVersion(entity); // '3.8' | '4.1' | '4.2'
const anims = manager.getAnimations(entity); // ['idle', 'run', 'jump']
const skins = manager.getSkins(entity); // ['default', 'warrior']
const bounds = manager.getBounds(entity); // { x, y, width, height }

多纹理批处理

使用多个图集页的 Spine 骨骼会被渲染器自动批处理。无需额外配置 — C++ 后端透明地处理多纹理情况,即使是复杂的多图集角色也能保持较低的 draw call。