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

来源:互联网 发布:彩虹源码安装 编辑:程序博客网 时间:2024/05/16 10:55

CocoStuido sample----SampleKeyFrameAnimation源代码地址: https://github.com/chukong/CocoStudioSamples  

大家可以预先下载这个源代码, 等下要用到里面的图片资源哦 。

在上面两篇教程中, 我们分别学习了序列帧动画( CocoStudio sample讲解 SampleFrameAnimation序列帧动画  )和关键帧动画 , 今天我们再来学习下骨骼动画在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  

  1. #include "cocos2d.h"  
  2. #include "cocos-ext.h"  
  3.   
  4. class  TestColliderDetector :  public cocos2d:: CCLayer 
  5. public  : 
  6.                 ~TestColliderDetector(); 
  7.     
  8.                  virtual  void  onEnter(); 
  9.                  virtual  void  update(  float  delta);  //检测对象位置,判断是否有碰撞  
  10.                  virtual  void  draw();  //绘制右边牛仔的碰撞区域  
  11.     
  12.                   //帧事件响应函数  
  13.                   void  onFrameEvent(cocos2d::extension:: CCBone *bone, const   char  *evt,  int originFrameIndex, intcurrentFrameIndex); 
  14.   
  15.                   //左边牛仔对象  
  16.                 cocos2d::extension:: CCArmature *armature; 
  17.                   //右边牛仔对象  
  18.                 cocos2d::extension:: CCArmature *armature2; 
  19.                   //子弹对象  
  20.                 cocos2d:: CCSprite * bullet; 
  21. }; 
  22.   
  23.   
  24. 再来看下TestColliderDetector.cpp   
  25. #include "TestColliderDetector.h"  
  26.   
  27. using namespace cocos2d; 
  28. using namespace cocos2d::extension; 
  29.   
  30. TestColliderDetector ::~TestColliderDetector() 
  31.                   //CCArmatureDataManager::purge();  
  32. void  TestColliderDetector ::onEnter() 
  33.                  CCLayer ::onEnter(); 
  34.                 scheduleUpdate();  //每帧都会调用update函数, 用于碰撞判断 
  35.     
  36.                   //加载动画数据  
  37.                  CCArmatureDataManager ::sharedArmatureDataManager()->addArmatureFileInfo( "Cowboy0.png" , "Cowboy0.plist"  , "Cowboy.ExportJson" ); 
  38.   
  39.                   //左边牛仔对象  
  40.                 armature = CCArmature ::create( "Cowboy"  ); 
  41.                 armature->getAnimation()->play(  "FireWithoutBullet" ); //播放FireWithoutBullet动画  
  42.                 armature->getAnimation()->setSpeedScale(0.2f);  //以0.2倍的速度播放, 牛仔动作会比较慢 
  43.                 armature->setScaleX(-0.2f);  //缩放牛仔, 并且让牛仔脸向右 
  44.                 armature->setScaleY(0.2f); 
  45.                 armature->setPosition( ccp (CCDirector ::sharedDirector()->getVisibleSize().width * 0.2, CCDirector ::sharedDirector()->getVisibleSize().height * 0.5)); 
  46.     
  47.                   //给左边牛仔对象绑定对象  
  48.                 armature->getAnimation()->setFrameEventCallFunc(  this  , frameEvent_selector (TestColliderDetector ::onFrameEvent)); 
  49.     
  50.                 addChild(armature); 
  51.     
  52.                   //右边牛仔对象  
  53.                 armature2 = cocos2d::extension:: CCArmature ::create( "Cowboy"  ); 
  54.                 armature2->getAnimation()->play(  "Walk"  ); //播放Walk动画  
  55.                 armature2->setScaleX(-0.2f);  //缩放牛仔, 并且让牛仔脸向右 
  56.                 armature2->setScaleY(0.2f); 
  57.                 armature2->setPosition( ccp (CCDirector ::sharedDirector()->getVisibleSize().width * 0.8, CCDirector ::sharedDirector()->getVisibleSize().height * 0.5)); 
  58.                 addChild(armature2); 
  59.   
  60.                   //创建子弹对象  
  61.                 bullet = CCSprite ::createWithSpriteFrameName( "25.png" ); 
  62.                 addChild(bullet); 
  63.   
  64. //我们刚才在编辑器中设置的帧事件会调用这个函数  
  65. void  TestColliderDetector ::onFrameEvent( CCBone * bone , const   char  * evt,  int originFrameIndex, intcurrentFrameIndex ) 
  66.      //获取武器所在节点的坐标  
  67.                  CCPoint p = armature->getBone( "gun"  )->getDisplayRenderNode()->convertToWorldSpaceAR( ccp (0, 0)); 
  68.     
  69.                   //设置子弹的坐标  
  70.                 bullet->setPosition( ccp (p.x + 60, p.y)); 
  71.                 bullet->stopAllActions(); 
  72.                   //子弹向右运动  
  73.                 bullet->runAction( CCMoveBy ::create(2.5f, ccp (CCDirector ::sharedDirector()->getVisibleSize().width, 0))); 
  74.   
  75. void  TestColliderDetector ::update(  float delta) 
  76.                   //先设置右边牛仔对象可见  
  77.                 armature2->setVisible(  true  ); 
  78.   
  79.                   //获取子弹的boundingBox区域, 用于碰撞检测  
  80.     CCRect rect = bullet->boundingBox(); 
  81.   
  82.      //逐一判断左边牛仔子节点中碰撞区域, 是否与子弹有相交之处  
  83.     CCDictElement *element = NULL ; 
  84.     CCDictionary *dict = armature2->getBoneDic(); 
  85.     CCDICT_FOREACH(dict, element) 
  86.     { 
  87.         CCBone *bone = static_cast < CCBone*>(element->getObject()); 
  88.         CCArray *bodyList = bone->getColliderBodyList(); 
  89.   
  90.         CCObject *object = NULL ; 
  91.         CCARRAY_FOREACH (bodyList, object) 
  92.         { 
  93.             ColliderBody *body = static_cast < ColliderBody*>(object); 
  94.             CCArray *vertexList = body->getCalculatedVertexList(); 
  95.   
  96.              float  minx, miny, maxx, maxy = 0; 
  97.              int  length = vertexList->count(); 
  98.              for  ( int  i = 0; i<length; i++) 
  99.             { 
  100.                 CCContourVertex2 *vertex = static_cast < CCContourVertex2*>(vertexList->objectAtIndex(i)); 
  101.                  if  (i == 0) 
  102.                 { 
  103.                   minx = maxx = vertex->x; 
  104.                   miny = maxy = vertex->y; 
  105.                 } 
  106.                  else  
  107.                 { 
  108.                     minx = vertex->x < minx ? vertex->x : minx; 
  109.                     miny = vertex->y < miny ? vertex->y : miny; 
  110.                     maxx = vertex->x > maxx ? vertex->x : maxx; 
  111.                     maxy = vertex->y > maxy ? vertex->y : maxy; 
  112.                 } 
  113.             } 
  114.             CCRect temp = CCRectMake (minx, miny, maxx - minx, maxy - miny); 
  115.   
  116.              if  (temp.intersectsRect(rect)) 
  117.             { 
  118.                                                                   //与子弹相交隐藏右边牛仔  
  119.                 armature2->setVisible(  false  ); 
  120.             } 
  121.         } 
  122.     } 
  123.   
  124. //绘制右边牛仔的碰撞区  
  125. void  TestColliderDetector ::draw() 
  126.                 armature2->drawContour(); 

赶快运行下你的代码, 看下效果吧!  

原帖:http://www.cocoachina.com/bbs/read.php?tid=189665

0 0
原创粉丝点击