CocoStuido sample----SampleCollision源代码地址
https://github.com/chukong/CocoStudioSamples
大家可以预先下载这个源代码, 等下要用到里面的图片资源哦
在上面两篇教程中, 我们分别学习了序列帧动画和关键帧动画, 今天我们再来学习下骨骼动画在CocoStudio中的制作. 骨骼动画由各个关节有机的结合起来, 并附着以皮肤. 当关节运动时, 相关的关节会一起运动, 以达到更加真实的动画效果.
一 目标

在本教程里, 我们将学习下如何用CocoStudio制作骨骼动画, 并在cocos2d-x运行, 还会有一些碰撞的基础.
我们使用的cocos2d-x的版本是2.2.2, CocoStudio的版本是1.2.0.1. 不同的版本, 功能上会有差异, 大家学习时, 最好采用对应的版本.
二 创建项目并导入资源
大家可以在下载到的源代码的SampleCollision\SampleCollision_Editor\DemoPlayer\DemoPlayer\Resources 目录下找到我们需要的图片资源
打开CocoStudio的动画编辑器, 并创建一个新的项目.
然后大家可以在资源面板点击导入文件的按钮, 导入这些资源文件. 导入后的资源面板如下.

三 构建形体
大家可以把资源面板中testAnimationResource目录下的牛仔身体各部位的图片都拖入渲染区, 然后可以通过拖动, 旋转等构建出形体模型. 我们在上一篇关键帧动画的教程中已经详细解释过, 大家可以参见下上一篇教程, 这里就不再赘述.
四 添加骨骼
我们可以在工具栏找到创建/停止创建骨骼的按钮, 以及隐藏/显示骨骼的按钮.

其中, 创建/停止创建骨骼的快捷键是Alt+K, 隐藏/显示骨骼的快捷键是Alt+G, 使用这些快捷键会让大家的工作更有效率.
让我们先给帽子添加一个骨骼吧.

如上图所示, 我们先点击创建骨骼按钮(建议用快捷键Alt+K), 从帽子的旋转点向上拖出骨骼.
然后再点击停止创建骨骼, 选中帽子, 点击鼠标右键,选择绑定到骨头(建议用快捷键Alt+I), 让后再点击下刚才为帽子创建的骨骼, 就完成了帽子的骨骼和图片的绑定. 拖动下骨骼, 就能看到, 帽子的图片可以随着骨骼旋转了.
接下来我们可以为其他节点创建依次创建并绑定骨骼.

绑定完骨骼, 我们就需要考虑这些骨骼的关系了. 比如身体要能带动腿, 腿要能带动脚.

如上图所示, 我们选中腿部骨骼, 在骨骼上点击右键, 选中绑定父关系(建议使用快捷键Alt+p), 然后再选中下身体的骨骼, 就完成了骨骼的父子绑定. 现在旋转下身体, 就能看到, 身体带动了腿脚一起运动.
我们这里把身体(披风)节点作为所有节点的父节点, 然后帽子, 胳膊左右腿作为子节点, 左右脚分别作为左右腿的子节点. 大家一一绑定即可, 这里就不啰嗦啦.
插播: 这里有点需要解释下
图片和骨骼的绑定, 其实是一个合并的过程. 合并后就只有骨骼的节点了, 图片作为骨骼的渲染资源, 不再是一个独立的节点.
五 骨骼动画的工具栏

编辑器的工具栏上还有几个常用的按钮,
- 逆时针旋转90度
- 顺时针旋转90度
- 将节点至于原点
后面的A,B,C,D是针对骨骼节点操作的几个模式.
A模式下可以旋转骨骼
B模式下可以移动骨骼
C模式下可以缩放骨骼
D模式是强大的反动力学模式, 希望以后有机会可以单独来讲这个.
六 制作动画
现在让我们切换到动画模式. 骨骼动画也是依靠关键帧来生成的, (我们在前面一篇教程已经详细地介绍了关键帧的添加方法, 如果大家不太熟悉关键帧用法请参见下上一篇教程), 我们简单地做一个帽子抖动的动作.
我们把时间轴游标拖动到第20帧, 选择帽子所在节点, 然后在渲染区给帽子移动,旋转到一个合适的位置.
然后点击下播放按钮, 是不是看到牛仔欢快地点起头来了?
大家可以按照源代码里面的Demo, 然后对照着练习一遍. 有什么问题, 可以随时到咱们的CocoaChina论坛的CocoStudio专区提出来哈.
七 添加帧事件
帧事件的意思就是当动画播放到该帧时触发一个事件. 比如, 刚才我们给牛仔添加了开枪的动作, 开枪就要有子弹, 子弹什么时候飞出捏? 飞出的时间肯定和动画相关. 那么我们就选择当武器抬起时, 子弹飞出.
做法就是在武器CocoStuido sample----SampleKeyFrameAnimation源代码地址抬起这一帧添加一个帧事件, 后面程序能识别出来这个事件, 执行子弹飞出的函数.
如上图所示, 我们在gun这个节点的第10帧添加了一个fire的帧事件. 稍后我们会在程序里面处理这个事件.
八 导出资源
用快捷键Ctrl+E打开导出对话框, 将图片最大宽度修改为2048, 选择导出的路径, 其他按默认配置我们得到了DemoPlayer.ExportJson DemoPlayer0.plist DemoPlayer0.png Comet.plist 这些文件. 我们稍后会用到这些文件.
九 在cocos2d-x工程中添加导出后的资源
想必各位看官都已经熟练掌握了cocos2d-x工程的创建, 我这里就不再啰嗦了.
创建完工程之后, 需要将我们上面用CocoStudio导出的几个文件拷贝到cocos2d-x工程的Resources文件夹下.
十 代码实现
我们要在cocos2d-x工程中实现两个牛仔, 一个走路, 一个打枪, 子弹和牛仔碰撞后, 牛仔消失一下.
代码中包含了普通, box2d, chipmunk三种碰撞判断, box2d, chipmunk这两种判断方式太过复杂, 我们这次就不再展开了, 只带大家看下普通的碰撞判断.
我们创建一个TestColliderDetector类, 包含TestColliderDetector.h 和 TestColliderDetector.cpp.
先来看下TestColliderDetector.h
#include “cocos2d.h”#include “cocos-ext.h”
class TestColliderDetector : public cocos2d:: CCLayer{public : ~TestColliderDetector(); virtual void onEnter(); virtual void update( float delta); //检测对象位置,判断是否有碰撞 virtual void draw(); //绘制右边牛仔的碰撞区域 //帧事件响应函数 void onFrameEvent(cocos2d::extension:: CCBone *bone, const char *evt, int originFrameIndex, intcurrentFrameIndex);
//左边牛仔对象 cocos2d::extension:: CCArmature *armature; //右边牛仔对象 cocos2d::extension:: CCArmature *armature2; //子弹对象 cocos2d:: CCSprite * bullet;};
再来看下TestColliderDetector.cpp
#include “TestColliderDetector.h”
using namespace cocos2d;using namespace cocos2d::extension;
TestColliderDetector ::~TestColliderDetector(){ //CCArmatureDataManager::purge();}void TestColliderDetector ::onEnter(){ CCLayer ::onEnter(); scheduleUpdate(); //每帧都会调用update函数, 用于碰撞判断 //加载动画数据 CCArmatureDataManager ::sharedArmatureDataManager()->addArmatureFileInfo( “Cowboy0.png”,“Cowboy0.plist” , “Cowboy.ExportJson”);
//左边牛仔对象 armature = CCArmature ::create(“Cowboy” ); armature->getAnimation()->play( “FireWithoutBullet” );//播放FireWithoutBullet动画 armature->getAnimation()->setSpeedScale(0.2f); //以0.2倍的速度播放, 牛仔动作会比较慢 armature->setScaleX(-0.2f); //缩放牛仔, 并且让牛仔脸向右 armature->setScaleY(0.2f); armature->setPosition( ccp (CCDirector ::sharedDirector()->getVisibleSize().width * 0.2, CCDirector ::sharedDirector()->getVisibleSize().height * 0.5)); //给左边牛仔对象绑定对象 armature->getAnimation()->setFrameEventCallFunc( this , frameEvent_selector (TestColliderDetector ::onFrameEvent)); addChild(armature); //右边牛仔对象 armature2 = cocos2d::extension:: CCArmature ::create(“Cowboy” ); armature2->getAnimation()->play( “Walk” );//播放Walk动画 armature2->setScaleX(-0.2f); //缩放牛仔, 并且让牛仔脸向右 armature2->setScaleY(0.2f); armature2->setPosition( ccp (CCDirector ::sharedDirector()->getVisibleSize().width * 0.8, CCDirector ::sharedDirector()->getVisibleSize().height * 0.5)); addChild(armature2);
//创建子弹对象 bullet = CCSprite ::createWithSpriteFrameName(“25.png” ); addChild(bullet);}
//我们刚才在编辑器中设置的帧事件会调用这个函数void TestColliderDetector ::onFrameEvent( CCBone * bone , const char * evt, int originFrameIndex, intcurrentFrameIndex ){ //获取武器所在节点的坐标 CCPoint p = armature->getBone(“gun” )->getDisplayRenderNode()->convertToWorldSpaceAR( ccp (0, 0)); //设置子弹的坐标 bullet->setPosition( ccp (p.x + 60, p.y)); bullet->stopAllActions(); //子弹向右运动 bullet->runAction( CCMoveBy ::create(2.5f, ccp (CCDirector ::sharedDirector()->getVisibleSize().width, 0)));}
void TestColliderDetector ::update( float delta){ //先设置右边牛仔对象可见 armature2->setVisible( true );
//获取子弹的boundingBox区域, 用于碰撞检测 CCRect rect = bullet->boundingBox();
//逐一判断左边牛仔子节点中碰撞区域, 是否与子弹有相交之处 CCDictElement *element = NULL ; CCDictionary *dict = armature2->getBoneDic(); CCDICT_FOREACH(dict, element) { CCBone bone = static_cast < CCBone>(element->getObject()); CCArray *bodyList = bone->getColliderBodyList();
CCObject *object = NULL ; CCARRAY_FOREACH (bodyList, object) { ColliderBody body = static_cast < ColliderBody>(object); CCArray *vertexList = body->getCalculatedVertexList();
float minx, miny, maxx, maxy = 0; int length = vertexList->count(); for (int i = 0; i<length; i++) { CCContourVertex2 vertex = static_cast < CCContourVertex2>(vertexList->objectAtIndex(i)); if (i == 0) { minx = maxx = vertex->x; miny = maxy = vertex->y; } else { minx = vertex->x < minx ? vertex->x : minx; miny = vertex->y < miny ? vertex->y : miny; maxx = vertex->x > maxx ? vertex->x : maxx; maxy = vertex->y > maxy ? vertex->y : maxy; } } CCRect temp = CCRectMake (minx, miny, maxx - minx, maxy - miny);
if (temp.intersectsRect(rect)) { //与子弹相交隐藏右边牛仔 armature2->setVisible( false ); } } }}
//绘制右边牛仔的碰撞区void TestColliderDetector ::draw(){ armature2->drawContour();}
赶快运行下你的代码, 看下效果吧!





楼主 好人一生平安!!!