工程1:LoadSpine:简单加载spine资源
建立工程,在层级上建立一个空对象,改名spine
在spine上添加spine组件: 添加组件>渲染组件>spine
在spine上挂上脚本loadspine
onLoad () {
cc.resources.load(
'loadSpine/alien-ess',
sp.SkeletonData,
this.newSpine.bind(this)
)
let canvas = cc.find('Canvas');
}
newSpine(err,res){
if(err){
cc.log("err")
}
let spine = this.getComponent(sp.Skeleton);
spine.skeletonData = res;
this.spineAnimate = spine.setAnimation(0,'run',true);
}
工程2:SpineAttach:骨架上的挂点
在项目中建立一个空对象改名raptor,并挂spine组件
在项目中建立5个按钮
@property(sp.Skeleton)
skeleton: sp.Skeleton = null;
@property(cc.Prefab)
targetPrefab: cc.Prefab = null;
@property(cc.Label)
modeLabel:cc.Label = null;
@property(cc.String)
redBoneName="";
@property(cc.String)
blueBoneName="";
@property(cc.String)
greenBoneName="";
// LIFE-CYCLE CALLBACKS:
// onLoad () {}
destoryAllNode(){
let attachUtil = this.skeleton.attachUtil;
attachUtil.destroyAllAttachedNodes();//销毁所有挂点
}
changeMode(){
let isCached = this.skeleton.isAnimationCached();//当前是否处于缓存模式
若想切换渲染模式,最好在设置'dragonAsset'之前,先设置好渲染模式,否则有运行时开销
if(isCached){
this.skeleton.setAnimationCacheMode(sp.Skeleton.AnimationCacheMode.REALTIME);
}else{
this.skeleton.setAnimationCacheMode(sp.Skeleton.AnimationCacheMode.SHARED_CACHE);
}
}
destorySomeNode(){
let attachUtil = this.skeleton.attachUtil;
attachUtil.destroyAttachedNodes(this.greenBoneName);//销毁对应的挂点
}
genetateSomeNodes(){
let attachUtil = this.skeleton.attachUtil;
let boneNodes = attachUtil.generateAttachedNodes(this.greenBoneName);
let boneNode = boneNodes[0];
if (boneNode) {
let targetNode = cc.instantiate(this.targetPrefab);
targetNode.color = cc.color(0, 255, 0);
boneNode.addChild(targetNode);
}
}
//btn_Add_Red_And_Blue
generateAllNodes(){
let attachUtil = this.skeleton.attachUtil;//挂点工具类 ,TS版本不全,自己去creator.d.ts 修改
attachUtil.generateAllAttachedNodes();遍历所有插槽,生成包含所有给定插槽名称的最小节点树,注意,调用该接口前请确保骨骼动画已经初始化好。
let boneNodes = attachUtil.getAttachedNodes(this.redBoneName);//获得对应的挂点
let boneNode = boneNodes[0];
if(boneNode){
let targetNode = cc.instantiate(this.targetPrefab);
targetNode.color = cc.color(255,0,0);
boneNode.addChild(targetNode);
}
let boneNodes1 = attachUtil.getAttachedNodes(this.blueBoneName);//获得对应的挂点
let boneNode1 = boneNodes1[0];
if(boneNode1){
let targetNode = cc.instantiate(this.targetPrefab);
// targetNode.color = cc.color(0,0,255); //蓝色 黑乎乎一片,这里先屏蔽了
boneNode1.addChild(targetNode);
}
}
注意:TS版本中有一些API不全,自己在 creator.d.ts 中改一下
creator.d.ts 的 API 顺序不稳定,小版本升级难比对 - Creator 2.x - Cocos中文社区
工程3:SpineBoy:角色 切换动作,时间缩放,调试插槽关节
一个spine对象 放在场景里
用按钮来控制
角色的各种动作
插槽的显隐
关节的显隐
时间的缩放:动画播放速度?
// Learn TypeScript:
// - https://docs.cocos.com/creator/2.4/manual/en/scripting/typescript.html
// Learn Attribute:
// - https://docs.cocos.com/creator/2.4/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
// - https://docs.cocos.com/creator/2.4/manual/en/scripting/life-cycle-callbacks.html
const {ccclass, property} = cc._decorator;
@ccclass
export default class SpineCtrl extends cc.Component {
@property(cc.Label)
label: cc.Label = null;
@property(Number)
mixTime: number = 0;
// LIFE-CYCLE CALLBACKS:
spineboySkeleton:sp.Skeleton;
_hasStop:boolean;
onLoad () {
this.spineboySkeleton = this.node.getComponent(sp.Skeleton);
this._setMix('walk','run');
this._setMix('run','jump');
this._setMix('walk','jump');
this._hasStop = false;
//用来设置开始播放动画的事件监听。
this.spineboySkeleton.setStartListener(trackEntry=>{
let animationName = trackEntry.animation ? trackEntry.animation.name : "";
cc.log("[track %s][animation %s] start.", trackEntry.trackIndex, animationName);
})
//用来设置动画被打断的事件监听。
this.spineboySkeleton.setInterruptListener(trackEntry=>{
let animationName = trackEntry.animation ? trackEntry.animation.name : "";
cc.log("[track %s][animation %s] interrupt.", trackEntry.trackIndex, animationName);
})
//用来设置动画播放完后的事件监听。
this.spineboySkeleton.setEndListener(trackEntry=>{
let animationName = trackEntry.animation ? trackEntry.animation.name : "";
cc.log("[track %s][animation %s] end.", trackEntry.trackIndex, animationName);
})
//用来设置动画将被销毁的事件监听。
this.spineboySkeleton.setDisposeListener(trackEntry=>{
let animationName = trackEntry.animation ? trackEntry.animation.name : "";
cc.log("[track %s][animation %s] will be disposed.", trackEntry.trackIndex, animationName);
})
//用来设置动画播放一次循环结束后的事件监听。
this.spineboySkeleton.setCompleteListener(trackEntry=>{
let animationName = trackEntry.animation ? trackEntry.animation.name : "";
if (animationName === 'shoot') {
this.spineboySkeleton.clearTrack(1);
}
var loopCount = Math.floor(trackEntry.trackTime / trackEntry.animationEnd);
cc.log("[track %s][animation %s] complete: %s", trackEntry.trackIndex, animationName, loopCount);
})
// 用来设置动画播放过程中帧事件的监听
this.spineboySkeleton.setEventListener((trackEntry,event)=>{
let animationName = trackEntry.animation ? trackEntry.animation.name : "";
cc.log("[track %s][animation %s] event: %s, %s, %s, %s", trackEntry.trackIndex, animationName, event.data.name, event.intValue, event.floatValue, event.stringValue);
})
}
toogleDebugSlots(){
this.spineboySkeleton.debugSlots = !this.spineboySkeleton.debugSlots;
}
toggleDebugBones(){
this.spineboySkeleton.debugBones = !this.spineboySkeleton.debugBones;
}
toggleTimeScale(){
if(this.spineboySkeleton.timeScale === 1.0){
this.spineboySkeleton.timeScale = 0.3;
}else{
this.spineboySkeleton.timeScale = 1.0;
}
}
stop(){
this.spineboySkeleton.clearTrack(0);
this._hasStop = true;
}
walk(){
this.spineboySkeleton.setAnimation(0,'walk',true);
this._hasStop = false;
}
run(){
this.spineboySkeleton.setAnimation(0,'run',true);
this._hasStop =false;
}
jump(){
let oldAnim = this.spineboySkeleton.animation;
this.spineboySkeleton.setAnimation(0,'jump',false);
if(oldAnim && !this._hasStop){
this.spineboySkeleton.addAnimation(0,oldAnim === 'run'?'run':'walk',true,0);
}
}
shoot(){
this.spineboySkeleton.setAnimation(1,'shoot',false);
}
start () {
}
_setMix(anim1,anim2){
this.spineboySkeleton.setMix(anim1,anim2,this.mixTime);
this.spineboySkeleton.setMix(anim2,anim1,this.mixTime);
}
// update (dt) {}
}
小问题:
尝试脚本生成spine对象,注意要实例化骨骼,否则setMix 会报错,