CocoStudio sample讲解 SampleCollision骨骼动画与简单碰撞

来源:互联网 发布:襄阳软件培训学校 编辑:程序博客网 时间:2024/05/04 22:39
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), 然后再选中下身体的骨骼, 就完成了骨骼的父子绑定. 现在旋转下身体, 就能看到, 身体带动了腿脚一起运动.  
我们这里把身体(披风)节点作为所有节点的父节点, 然后帽子, 胳膊左右腿作为子节点, 左右脚分别作为左右腿的子节点. 大家一一绑定即可, 这里就不啰嗦啦.  
插播: 这里有点需要解释下  
图片和骨骼的绑定, 其实是一个合并的过程. 合并后就只有骨骼的节点了, 图片作为骨骼的渲染资源, 不再是一个独立的节点.  
五 骨骼动画的工具栏  

  
编辑器的工具栏上还有几个常用的按钮,  
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 * evtint originFrameIndexintcurrentFrameIndex )
{
    //获取武器所在节点的坐标
                 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();
}
 
 
赶快运行下你的代码, 看下效果吧!  
0 0
原创粉丝点击