Spine 动画
SpineAnimation 组件播放 Spine 骨骼动画。在场景编辑器中将它和 LocalTransform 一起添加到实体上。
属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
skeletonPath | string | '' | 骨骼 JSON 文件路径 |
atlasPath | string | '' | 图集文件路径 |
skin | string | '' | 当前皮肤名 |
animation | string | '' | 当前动画名 |
timeScale | number | 1.0 | 播放速度倍率 |
loop | boolean | true | 是否循环 |
playing | boolean | true | 是否正在播放 |
flipX | boolean | false | 水平翻转 |
flipY | boolean | false | 垂直翻转 |
color | Color | {r:1, g:1, b:1, a:1} | 着色 RGBA |
layer | number | 0 | 渲染顺序 |
skeletonScale | number | 1.0 | 骨骼缩放因子 |
material | number | 0 | 材质 ID |
设置步骤
- 将 Spine 导出文件(
.json+.atlas+ 图片)放到项目的assets/文件夹 - 在场景编辑器中:创建实体 → 添加
LocalTransform和SpineAnimation - 设置
skeletonPath和atlasPath指向 Spine 文件 - 设置
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, LocalTransform, SpineAnimation} from 'esengine';
const CharacterState = defineComponent('CharacterState', { speed: 200, currentAnim: 'idle'});
addSystem(defineSystem( [Res(Input), Res(Time), Query(Mut(LocalTransform), Mut(SpineAnimation), 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; } } }));