版本: 3.4.0
参考:
简介
使用spine动画,cocosCreator目前支持的版本:
creator版本 | spine版本 |
---|---|
V3.0 及以上 | v3.8(原生平台不支持特定版本 v3.8.75) |
v2.3 及以上 | v3.8 |
v2.2 | v3.7 |
v2.0.8~v2.1 | v3.6 |
v2.0.7 及以下 | v2.5 |
spine骨骼动画所需资源主要有如下三种:
.png
动画图片相关.txt/.atlas
图集配置数据相关.json/.skel
骨骼数据配置相关
spine骨骼动画主要组成部分:
bones
骨骼相关,基本组成元素,存在父子关系;每个骨骼可关联多个slot
相关slots
插槽相关, 主要用于关联多个attachment
相关attachment
附件相关, 有Mesh, BoundingBox, SkinnedMesh等不同类型skins
皮肤相关animations
动画相关ik
在cocosCreator中使用spine动画,官方封装的组件是sp.Skeleton
。
sp.Skeleton组件的使用
通过编译器添加spine动画,大概步骤:
- 在层级管理器创建一个空节点,假设命名为
spine_node
- 在
spine_node
的属性检查器中,添加组件,搜索skeleton
添加进来 - 可把
UITransform
的锚点修改为(0.5, 0)
注意: spine骨骼动画在CocosCreator中的组件类型是
sp.Skeleton
,不是spine。
如果在代码中通过@property
使用,节点可通过getComponent(sp.Skeleton)
获取。
export class DebugLayer extends Component {
@property(Node)
spineNode: Node = null;
private _spine: sp.Skeleton = null;
onLoad() {
this._spine = this.spineNode.getComponet(sp.Skeleton);
}
onEnable() {
// 使用Node类型,可以添加对spine动画的触摸事件
this.spineNode.on(Node.EventType.TOUCH_END, this._touchSpineEvent, this);
}
private _touchSpineEvent() {
console.log("you touch spine");
}
}
cocosCreator通过Skeleton对spine骨骼动画封装了很多方法, 常用属性或接口有:
属性接口 | 返回类型 | 说明 |
---|---|---|
loop | boolean | 是否循环播放 |
paused | boolean | 当前骨骼动画是否暂停 |
animation | string | 当前播放的动画名称 |
timeScale | number | 设置动画播放速度,数值越大,速度越快 |
debugSlots | boolean | 是否显示slot的测试信息 |
debugBones | boolean | 是否显示bone的测试信息 |
debugMesh | boolean | 是否显示mesh的测试信息 |
useTint | boolean | 是否启用染色效果 |
setSkin() | void | 设置皮肤,比如切换衣服 |
setAttachment() | void | 设置附件,比如切换武器 |
setMix() | void | 设置两个动画的混合时间,用于优化动画之间切换不连贯 |
setAnimation() | TrackEntry | 设置当前动画,不管前面是否播放动画,直接停止,然后播放设置的动画 |
addAnimation() | TrackEntry | 添加动画,当前的动画单次播放结束后,开始播放 |
setToSetupPose() | void | 还原到起始动作, 它主要用于处理上个动作留下的残影效果 |
findBone() | spine.Bone | 根据骨骼名字获取骨骼信息 |
findSlot() | spine.Slot | 根据关节名字获取关节信息 |
setStartListener() | void | 事件回调, 设置开始播放动画的事件监听 |
setInterruptListener() | void | 事件回调, 设置动画被打断的事件监听 |
setEndListener() | void | 事件回调, 设置动画播放完后的事件监听 |
setDisposeListener() | void | 事件回调, 设置动画将被销毁的事件监听 |
setCompleteListener() | void | 事件回调, 设置播放一次循环结束后的事件监听 |
setEventListener() | void | 事件回调, 设置动画播放过程中帧事件的监听 |
简单的示例:
export class UI_SpineLayer extends Component {
@property(sp.Skeleton)
spine: sp.Skeleton = null!; \
onLoad() {
// 设置播放速度
this.spine.timeScale = 0.6;
// 设置两个动画之间的混合时间
this.spine.setMix("walk", "run", 0.2);
// 设置当前动画播放, trackIndex一般默认0即可
this.spine.setAnimation(0, "walk", true);
// 设置当前皮肤
this.spine.setSkin("boy");
// spine动画单次循环结束回调相关
this.spine.setCompleteListener((trackEntry) => {
let track = trackEntry.trackIndex;
let aniName = trackEntry.animation ? trackEntry.animation.name : "";
let loopCount = Math.floor(trackEntry.trackTime/trackEntry.animationEnd);
if (aniName === "walk") {
this.spine.timeScale = 1;
this.spine.setToSetupPose();
this.spine.setAnimation(trackIndex, "run", true);
}
});
}
public ChangeSkinEvent() {
this.spine.setSkin("girl"); // 更换皮肤
}
}
spine动画动态加载
在实际的项目中开发,spine动画动态加载是不可避免的, 这里提供一个简单的封装接口:
public loadSpine(spineNode: Node, resUrl: string, skinName: string = "default", aniName: string = "default", isLoop: boolean = true) {
if (!spineNode || !spineNode.isValid) {
console.error("loadSpine node null!!!");
return;
}
spineNode.active = false;
// 检测能否获取到已缓存的资源
let spine = spineNode.getComponent(sp.Skeleton);
let skeletonData: sp.SkeletonData = resources.get(resUrl);
if (skeletonData) {
spineNode.active = true;
spine.skeletonData = skeletonData;
spine.setSkin(aniName);
spine.setAnimation(0, aniName, isLoop);
// spineNode.active = true; // Error
return;
}
resources.load(resUrl, sp.SkeletonData, (err: Error, sd: sp.SkeletonData) => {
if (err) {
return console.error(err.message);
}
// 动态加载为异步,因此增加下安全判定
if (spineNode && spineNode.isValid) {
spineNode.active = true;
spine!.skeletonData = skeletonData;
spine!.setSkin(aniName);
spine!.setAnimation(0, aniName, isLoop);
// spineNode.active = true; // Error
}
});
}
注: 关于spineNode的
active
不可放在最后面,否则动画能够正常加载,但不能正常播放。