Spine动画的几个使用技巧

2,121 阅读6分钟

本文所有的例子都基于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文件并打开

效果如下:

image-2024-7-29_19-14-28.png

核心功能

1、查看并切换Animation,也就是动画段

2、查看并切换skin

3、可以操作和查看多Track混合动画的效果

4、调整播放速度和Mix

5、Debug,可以查看资源中的所有骨头(Bone)、区域(Regions)等等,这块还有一些术语没有去专门学习,比如Clipping、Mesh hull这些

流畅的动画过渡

Spine动画中,我们操作最多的应该就是通过addAnimation和setAnimation去改变动画状态,其实从最初就有过这样一个疑惑:Spine中的每一个动画状态(State)感觉是相互独立的,那么如何来保障切换状态时的平滑过渡呢?答案就是通过Mix

在不设置Mix的情况下,动画切换的示例视频如下:

ba394344-bf28-4dd2-9e4f-9175d14cc9eb.gif

可以看到,动画之间衔接时有着明显的突变效果

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);

设置后的效果:

2.gif

监听点击事件

监听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;
});

效果如下:

3.gif

点击红色的区域就可以触发相应的事件,但是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的动画效果进行混合

4.gif

Track Alpha

上面的例子中,其实和直接在轨道0上切换动画没啥区别,好像也没有体现出什么不一样的效果。是因为上面的代码,没有体现出多track使用中的另外一个重要概念,即Track Alpha,还是先看一下官方的文档解释:

image-2024-7-31_14-30-19.png

这段解释非常重要,不仅说明了alpha的含义,同时还给出了多track的实践方式

设置track alpha的方式其实也非常简单:

// ipSpine是通过pixi-spine创建的spine对象
const track = ipSpine.state.tracks[trackIndex];
if (track) {
  track.alpha = XXXX;
}

看一下效果:

5.gif

虽然视频中的效果有点鬼畜了,但是仍然可以看到,在视频中,随着track1的alpha值变小,track1的动画效果也在逐步减弱,直观体现就是ip人物跳的越来越矮了

结语

推荐大家可以看一下Spine官方的运行时示例,其中还有很多例子可以学习和参考,地址如下:github.com/EsotericSof…