Cocos引擎中的骨骼动画使用过程与序列帧动画相同,一般都是先在Cocos Studio里编辑动画,然后在在工程代码中加载和使用动画,这篇博客就来详细介绍下具体步骤:
一.使用CocosStudio编辑骨骼动画
该过程步骤与使用CocosStudio编辑序列帧动画相似,区别就是导入的动画资源与绑定的控件不同:
1.首先创建一个场景:文件->新建文件,名字叫“AnimationTest”:
2.向场景添加一个基础容器,相当于一个层,并设置其坐标、尺寸:
3.导入骨骼动画资源:这里需要说明一下,动画资源一共需要3个文件:一个.ExportJson文件,一个.plist文件和一个.png文件。ExportJson文件中记录了骨骼动画的描述信息,plist文件则是记录碎图整合成大图后图片的位置描述信息,png文件是整合的大图。导入时只需导入ExportJson文件,但这不意味着就不需要.plist文件和一个.png文件,如果没有这两个文件导入资源时就不会导入成功。这几个资源一般是由美工来编辑的,Cocos Studio新版本不支持编辑骨骼动画的功能。
4.添加Armature控件:在左侧的自定义控件中选取Armature控件,直接拖动到当前场景上即可,新创建的Armature控件会默认绑定一个牛仔的骨骼动画,我们可以用自己的骨骼动画来替换掉它。
5.将骨骼动画资源文件绑定到Armature控件上,也是直接拖动即可,将ExportJson文件拖到Armature控件的“属性”-“特性”-“文件”中。另外,在“属性”-“特性”-“动画列表”下拉栏中可以看到该骨骼动画的所有动作,每一个动作都有对应的名字,我这个骨骼动画里面有run、loading、attack、smitten、death等动作,它们的序号从0开始依次向后排,我们在代码中可以通过它们的动作名或序号来获得这些动作。
6.编辑完骨骼动画后要保存和发布项目,这样会在我们的项目工程中Resources/res目录下会生成一个AnimationTest.csb文件,这个文件就是我们所创建的这个场景的配置文件,代码中就是通过加载这个文件使用我们的骨骼动画的。
二.在代码中使用Cocos Studio编辑的骨骼动画
打开项目工程文件,在HelloWorldScene.cpp中添加代码。
首先要添加CCArmature.h的命名空间:
using namespace cocostudio;
然后在HelloWorld::init()方法中修改代码:
1.播放我们编辑的骨骼动画:
//加载骨骼动画所在场景的node auto rootNode = CSLoader::createNode("AnimationTest.csb"); addChild(rootNode); //获得骨骼动画 Armature* arm =(Armature*) rootNode->getChildByName("Panel_1")->getChildByName("ArmatureNode_1"); //播放骨骼动画 //参数:1.动画索引,起始为0 2.动画之间是否有衔接帧 3.是否循环播放arm->getAnimation()->playWithIndex(2,-1,1); //还可以通过动作名来播放动画 arm->getAnimation()->play("run");
运行效果我就不弄动态的了吧,给大家截一张图,反正可以看到我们的帅哥跑起来了:
2.此外,我们还可以给骨骼动画添加回调函数:
1).在头文件中声明骨骼动画的回调函数:
void onMovementEvent(Armature* arm,MovementEventType type,const std::string&actionName);
给骨骼动画添加回调函数后,当执行动画时某些事件被触发,其回调函数内部就会被执行。你可能会想这些事件都是什么呢?这里我们看一下第二个参数MovementEventType的事件类型定义:
enum MovementEventType { START, COMPLETE, LOOP_COMPLETE };
可以看到,这3个事件类型分别为动作的开始、完成和循环完成,循环完成就是当动画循环播放时每播放完一次会触发一次的事件。另外,函数声明中的第一个和第三个参数分别是骨骼动作的索引以及动作名称。
2).绑定骨骼动画的回调函数:
</pre><pre name="code" class="cpp">arm->getAnimation()->setMovementEventCallFunc(CC_CALLBACK_0(HelloWorld::onMovementEvent, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
注意,绑定回调函数用了setMovementEventCallFunc()方法,调用这个方法的执行者就是我们创建的Armature对象;该方法的参数是一个CC_CALLBACK_0宏函数,此宏函数的参数,前两个为回调函数以及回调函数所属类,后面3个具体是啥我还没研究,反正是利用了C++11的某些新特性。
3).回调函数的实现:
这里我只是用回调函数打印出回调事件类型以及骨骼动画的动作名:
void HelloWorld::onMovementEvent(cocostudio::Armature *arm, cocostudio::MovementEventType type, const std::string &actionName) { if (type == MovementEventType::START) { log("START"); } if (type == MovementEventType::COMPLETE) { log("COMPLETE"); } if (type == MovementEventType::LOOP_COMPLETE) { log("LOOP_COMPLETE"); } log("name = %s", actionName.c_str()); }
打印结果如下:
可以看到,由于我们的这个骨骼动画是循环播放的,每播放完一次都会执行一次回调函数。我们可以利用骨骼动画的回调函数做很多事,比如播放受击动画时,播放结束后可以在其回调函数中判断主角是否还有血,如果没血了就可播放其死亡动画。所以说回调函数就是给了我们一个时间点去操作一些逻辑。
以上。