帧动画与骨骼动画的区别在于:帧动画的每一帧都是角色特定姿势的一个快照,动画的流畅性和平滑效果都取决于帧数的多少。而骨骼动画则是把角色的各部分身体部件图片绑定到一根根互相作用连接的“骨头”上,通过控制这些骨骼的位置、旋转方向和放大缩小而生成的动画。
它们需要的图片资源各不相同,如下分别是帧动画和骨骼动画所需的资源图:
骨骼动画比传统的逐帧动画要求更高的处理器性能,但同时它也具有更多的优势,比如:
Spine是一款针对游戏的2D骨骼动画编辑工具,它具有良好的UI设计和完整的功能,是一个比较成熟的骨骼动画编辑器。Spine旨在提供更高效和简洁的工作流程,以创建游戏所需的动画。
使用Spine创建骨骼动画分两大步骤:
下面简单介绍下具体步骤,更多详细内容请查看官方网站教程:Spine快速入门教程。
1)在SETUP模式下,选中Images属性,导入所需图片资源所在文件夹,其中路径名和资源名中不能出现中文,否则解析不了;
2)拖动Images下的图片到场景,对角色进行组装(把各个身体部位拼在一起),可通过Draw Order属性调整图片所在层的顺序;
3)创建骨骼,并绑定图片到骨骼上,要注意各骨骼的父子关系。
4)切换到ANIMATE模式,选中要“动”的骨骼,对其进行旋转、移动、缩放等操作,每次改动后要记得打关键帧。
5)在菜单栏找到Texture Packer项,对角色纹理进行打包,资源文件后缀为atlas(而非Cocos2d-x常用的plist)。打包后将生成两个文件,即:png 和 atlas。
6)导出动画文件Json。
Cocos2d-x程序中,使用Spine动画首先需要包含spine的相关头文件。
1
2
3
|
#include
#include "spine/spine.h"
using namespace spine;
|
其常用方法如下:
创建一个Spine动画对象,将动画文件和资源文件导入。
1
|
auto skeletonNode = new SkeletonAnimation( "enemy.json" , "enemy.atlas" );
|
骨骼动画往往是不止一个动画的,例如:当人物需要行走时,就设置播放动画为行走;当要发动攻击时,就设置播放动画为攻击。下面方法可以设置当前播放动画,其中参数false表示不循环播放,true表示循环播放。
1
|
skeletonNode->setAnimation(0, "walk" , true );
|
setAnimation方法只能播放一种动画,所以当要连续播放不同的动画时,需要使用addAnimation方法来实现,它可以一条一条的播放不同的动画。
1
2
|
skeletonNode->addAnimation(0, "walk" , true );
skeletonNode->addAnimation(0, "attack" , false );
|
对于一般情况下,动画的切换要求两个动画完全能衔接上,不然会出现跳跃感,这个对于美术来说要求很高,而Spine加了个动画混合的功能来解决这个问题。使得不要求两个动画能完全的衔接上,比如上面的walk和attack动画, 就是衔接不上的,直接按上面的办法播放,会出现跳跃,但是加了混合后,看起来就很自然了。哪怕放慢10倍速度观察,也完美无缺。这个功能在序列帧动画时是无法实现的,也是最体现Spine价值的一个功能。
1
2
|
skeletonNode->setMix( "walk" , "attack" , 0.2f);
skeletonNode->setMix( "attack" , "walk" , 0.4f);
|
设置动画的播放快慢可通过设置它的timeScale值来实现。
1
|
skeletonNode->timeScale = 0.6f;
|
设置是否显示骨骼通过设置debugBones,true表示显示,false表示隐藏。
1
|
skeletonNode->debugBones = true ;
|
例子:创建一个player行走和攻击的动画, 并且循环播放。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
auto skeletonNode = new SkeletonAnimation( "enemy.json" , "enemy.atlas" );
skeletonNode->setMix( "walk" , "attack" , 0.2f);
skeletonNode->setMix( "attack" , "walk" , 0.4f);
skeletonNode->setAnimation(0, "walk" , false );
skeletonNode->setAnimation(0, "attact" , false );
skeletonNode->addAnimation(0, "walk" , false );
skeletonNode->addAnimation(0, "attact" , true );
skeletonNode->debugBones = true ;
Size windowSize = Director::getInstance()->getWinSize();
skeletonNode->setPosition(Point(windowSize.width / 2, windowSize.height / 2));
addChild(skeletonNode);
|
效果图: