工程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_BluegenerateAllNodes(){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.htmlconst {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 会报错,