本文所有的例子都基于pixi 7.x、pixi-spine 4.x版本
预览Spine资源
这是Spine官方出的预览工具,看下官方的介绍:
Skeleton Viewer是一个可以加载和显示skeleton数据的工具。它与Preview视图非常相似,对于测试从Spine导出的skeleton数据是如何使用Spine Runtime进行渲染的非常有用.
理论上,可以把这个工具视为设计师和研发之间的一个对接桥梁,正如官方所说,它和设计软件的Preview视图非常相似
如何使用
1、到官网下载相应的版本:zh.esotericsoftware.com/spine-skele…
2、安装Java环境,需要Java9+
3、命令行cd到jar包所在的目录,运行:
# skeletonViewer.jar为实际的jar包文件名称
java -jar skeletonViewer.jar
4、点击左上角的"Open"按钮,找到本地的.skel文件并打开
效果如下:
核心功能
1、查看并切换Animation,也就是动画段
2、查看并切换skin
3、可以操作和查看多Track混合动画的效果
4、调整播放速度和Mix
5、Debug,可以查看资源中的所有骨头(Bone)、区域(Regions)等等,这块还有一些术语没有去专门学习,比如Clipping、Mesh hull这些
流畅的动画过渡
Spine动画中,我们操作最多的应该就是通过addAnimation和setAnimation去改变动画状态,其实从最初就有过这样一个疑惑:Spine中的每一个动画状态(State)感觉是相互独立的,那么如何来保障切换状态时的平滑过渡呢?答案就是通过Mix
在不设置Mix的情况下,动画切换的示例视频如下:
可以看到,动画之间衔接时有着明显的突变效果
Mix的使用方法
其实非常简单,本质上就是为动画状之间设置一个过渡时间,一般有2种使用方式:
1、设置defaultMix
// ipSpine是通过pixi-spine创建的spine对象
ipSpine.state.data.defaultMix = 0.3;
2、单独设置2个动画之间的mix
// ipSpine是通过pixi-spine创建的spine对象
ipSpine.state.data.setMix('walk', 'run', 0.3);
设置后的效果:
监听点击事件
监听Spine对象的整体点击
一开始,我们遇到需要监听Spine元素点击事件的需求时,做法通常是在Spine动画元素上面盖一个透明的div或者svg,然后再给盖上去的元素添加Listener来实现,虽然也能用,但是也增加了开发负担。
pixi-spine中有内置的监听事件的能力,示例代码如下:
// ipSpine是通过pixi-spine创建的spine对象
ipSpine.interactive = true;
ipSpine.on('pointerdown', handler);
是的,就是这么简单!并且这种实现方式,如果用户点击了透明区域,则是不会触发的,也规避了盖一层div所导致的副作用
额外说明一下,pixi-spine中的pointerdown(本质上是pixi中的能力),和我们DOM中的pointerdown event不一样,DOM中的pointerdown event是有兼容性问题的,但是pixi-spine中的pointerdown没有兼容性问题,可放心使用
除了pointerdown,还有其他很多事件可以监听,包括:
-
added: 当对象被添加到容器中时触发。
-
removed: 当对象从容器中移除时触发。
-
pointerdown: 当指针(鼠标或触摸)按下时触发。
-
pointerup: 当指针(鼠标或触摸)抬起时触发。
-
pointermove: 当指针(鼠标或触摸)移动时触发。
-
pointerover: 当指针(鼠标或触摸)悬停在对象上时触发。
-
pointerout: 当指针(鼠标或触摸)离开对象时触发。
监听Spine对象中的部分区域点击
上面的这种方式,目前只能支持监听整个Spine元素的点击行为,如果只想监听特定区域的点击呢?由于pixi-spine中的骨骼、插槽都不是pixi的DisplayObject,因此没法像上面的方式来做。有一个思路是:根据特定骨骼的大小和位置,手动在pixi中创建一个可交互区,并对这个交互区添加事件监听。同时需要在pixi app的每一个ticker中根据骨骼的位置随时更新交互区的位置
// 下面的示例为给骨骼添加点击事件
const hitArea = new PIXI.Graphics();
hitArea.beginFill('ff00ff'); // 透明填充
hitArea.drawRect(0, 0, 30, 30); // 假设区域大小为30*30
hitArea.endFill();
hitArea.x = 0;
hitArea.y = 0;
// 启用交互
hitArea.interactive = true;
hitArea.on('pointerdown', this.clickHandler);
// 将交互区域添加到Spine对象
ipSpine.addChild(hitArea);
// 找到骨骼,并根据骨骼的位置随时更新交互区的位置
const bone = ipSpine.skeleton.findBone('bd_shouzuo') as any;
app.ticker.add(() => {
// 更新交互区域位置
hitArea.x = bone.worldX;
hitArea.y = bone.worldY;
});
效果如下:
点击红色的区域就可以触发相应的事件,但是ip人物跳起来之后还是有一些细节问题
混合动画
基本使用
addAnimation和setAnimation这两个方法中的第一个参数,一般情况下我们都是默认写0,这个参数的含义是trackIndex,这就引出了spine运行时中的另外一个重要概念:多轨道混合动画,就是说,我们可以在不同轨道上叠加动画。
我们可以看下spine运行时官方demo中的说法:
zh.esotericsoftware.com/spine-demos…
在不同的轨道上播放动画时,通常较低轨道的姿势会被较高轨道覆盖。使用相加轨道时,其姿势将被添加到较低轨迹的轨道中。这可混合来自具有不同影响的多个独立动画的姿势,例如50%快乐、20%疯狂和30%兴奋的不同面部表情。
使用的方式则非常简单:
// ipSpine是通过pixi-spine创建的spine对象
state.setAnimation(0, 'normal', true);
state.setAnimation(1, 'praise', true);
通过这2行代码,就可以将normal和praise的动画效果进行混合
Track Alpha
上面的例子中,其实和直接在轨道0上切换动画没啥区别,好像也没有体现出什么不一样的效果。是因为上面的代码,没有体现出多track使用中的另外一个重要概念,即Track Alpha,还是先看一下官方的文档解释:
这段解释非常重要,不仅说明了alpha的含义,同时还给出了多track的实践方式
设置track alpha的方式其实也非常简单:
// ipSpine是通过pixi-spine创建的spine对象
const track = ipSpine.state.tracks[trackIndex];
if (track) {
track.alpha = XXXX;
}
看一下效果:
虽然视频中的效果有点鬼畜了,但是仍然可以看到,在视频中,随着track1的alpha值变小,track1的动画效果也在逐步减弱,直观体现就是ip人物跳的越来越矮了
结语
推荐大家可以看一下Spine官方的运行时示例,其中还有很多例子可以学习和参考,地址如下:github.com/EsotericSof…