CocoStuido sample----SampleKeyFrameAnimation源代码地址
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), 然后再选中下身体的骨骼, 就完成了骨骼的父子绑定. 现在旋转下身体, 就能看到, 身体带动了腿脚一起运动.
我们这里把身体(披风)节点作为所有节点的父节点, 然后帽子, 胳膊左右腿作为子节点, 左右脚分别作为左右腿的子节点. 大家一一绑定即可, 这里就不啰嗦啦.
插播: 这里有点需要解释下
图片和骨骼的绑定, 其实是一个合并的过程. 合并后就只有骨骼的节点了, 图片作为骨骼的渲染资源, 不再是一个独立的节点.
五 骨骼动画的工具栏
编辑器的工具栏上还有几个常用的按钮,
1. 逆时针旋转90度
2. 顺时针旋转90度
3. 将节点至于原点
后面的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
再来看下TestColliderDetector.cpp
赶快运行下你的代码, 看下效果吧!
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), 然后再选中下身体的骨骼, 就完成了骨骼的父子绑定. 现在旋转下身体, 就能看到, 身体带动了腿脚一起运动.
我们这里把身体(披风)节点作为所有节点的父节点, 然后帽子, 胳膊左右腿作为子节点, 左右脚分别作为左右腿的子节点. 大家一一绑定即可, 这里就不啰嗦啦.
插播: 这里有点需要解释下
图片和骨骼的绑定, 其实是一个合并的过程. 合并后就只有骨骼的节点了, 图片作为骨骼的渲染资源, 不再是一个独立的节点.
五 骨骼动画的工具栏
编辑器的工具栏上还有几个常用的按钮,
1. 逆时针旋转90度
2. 顺时针旋转90度
3. 将节点至于原点
后面的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();
}
赶快运行下你的代码, 看下效果吧!