跳转到内容

Spine 动画

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

属性

属性类型默认值说明
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

设置步骤

  1. 将 Spine 导出文件(.json + .atlas + 图片)放到项目的 assets/ 文件夹
  2. 在场景编辑器中:创建实体 → 添加 LocalTransformSpineAnimation
  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, 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;
}
}
}
));