【转】Cocos2d-x 2.0 拖尾效果深入分析

时间:2021-02-19 11:22:41

Cocos2d-x 2.0 拖尾效果深入分析

另:本章所用Cocos2d-x版本为:

cocos2d-2.0-x-2.0.2@ Aug 30 2012

http://cn.cocos2d-x.org/download

今天我们来学习一下Cocos2d-x中的拖尾效果。在游戏中,拖尾效果常常用来做刀光,火球法术等一些运动物体的效果。如图:

【转】Cocos2d-x 2.0 拖尾效果深入分析

在Cocos2d-x中,拖尾效果有一个专门的类CCMotionStreak来实现。下面我们打开CCMotionStreak.h来看一下:

[cpp] view plaincopy

  1. #ifndef __CCMOTION_STREAK_H__
  2. #define __CCMOTION_STREAK_H__
  3. #include “CCProtocols.h”
  4. #include “textures/CCTexture2D.h”
  5. #include “ccTypes.h”
  6. #include “base_nodes/CCNode.h”
  7. //使用Cocos2d命名空间
  8. NS_CC_BEGIN
  9. //条带由三个基类共同派生
  10. class CC_DLL CCMotionStreak : public CCNode, public CCTextureProtocol, public CCRGBAProtocol
  11. {
  12. public:
  13. //构造
  14. CCMotionStreak();
  15. //析构
  16. virtual ~CCMotionStreak();
  17. //静态函数,创建一个拖尾效果,内部调用create实现,参一为消隐动画时长,参二为拖尾条带相邻顶点间的最小距离,参三为拖尾条带的宽度,参四为顶点颜色值,参五为所使用的纹理图片。
  18. CC_DEPRECATED_ATTRIBUTE static CCMotionStreak* streakWithFade(float fade, float minSeg, float stroke, ccColor3B color, const char* path);
  19. //静态函数,创建一个拖尾效果,内部调用create实现,参一为消隐动画时长,参二为拖尾条带相邻顶点间的最小距离,参三为拖尾条带的宽度,参四为顶点颜色值,参五为所使用的纹理对象指针。
  20. CC_DEPRECATED_ATTRIBUTE static CCMotionStreak* streakWithFade(float fade, float minSeg, float stroke, ccColor3B color, CCTexture2D* texture);
  21. //上面第一个创建函数的create实现。
  22. static CCMotionStreak* create(float fade, float minSeg, float stroke, ccColor3B color, const char* path);
  23. //上面第二个创建函数的create实现。
  24. static CCMotionStreak* create(float fade, float minSeg, float stroke, ccColor3B color, CCTexture2D* texture);
  25. //初始化拖尾效果
  26. bool initWithFade(float fade, float minSeg, float stroke, ccColor3B color, const char* path);
  27. //初始化拖尾效果
  28. bool initWithFade(float fade, float minSeg, float stroke, ccColor3B color, CCTexture2D* texture);
  29. //
  30. void tintWithColor(ccColor3B colors);
  31. //重置,删除所有的条带段
  32. void reset();
  33. //设置位置
  34. virtual void setPosition(const CCPoint& position);
  35. //绘制
  36. virtual void draw();
  37. //更新
  38. virtual void update(float delta);
  39. //取得纹理。
  40. virtual CCTexture2D* getTexture(void);
  41. //设置纹理。
  42. virtual void setTexture(CCTexture2D *texture);
  43. //设置
  44. virtual void setBlendFunc(ccBlendFunc blendFunc);
  45. virtual ccBlendFunc getBlendFunc(void);
  46. //设置颜色
  47. virtual void setColor(const ccColor3B& color);
  48. virtual const ccColor3B& getColor(void);
  49. //设置透明度
  50. virtual GLubyte getOpacity(void);
  51. virtual void setOpacity(GLubyte opacity);
  52. nbsp;          i2 *= 4;
  53. newIdx2 *= 4;
  54. m_pColorPointer[newIdx2+0] = m_pColorPointer[i2+0];
  55. m_pColorPointer[newIdx2+1] = m_pColorPointer[i2+1];
  56. m_pColorPointer[newIdx2+2] = m_pColorPointer[i2+2];
  57. m_pColorPointer[newIdx2+4] = m_pColorPointer[i2+4];
  58. m_pColorPointer[newIdx2+5] = m_pColorPointer[i2+5];
  59. m_pColorPointer[newIdx2+6] = m_pColorPointer[i2+6];
  60. }else
  61. newIdx2 = newIdx*8;//如果mov等于0,则R,G,B值不用变,只修改A值即可。
  62. //将当前顶点原来的颜色顶点缓冲中Alpha值保存到顶点缓冲新位置Alpha值中。
  63. const GLubyte op = (GLubyte)(m_pPointState[newIdx] * 255.0f);
  64. m_pColorPointer[newIdx2+3] = op;
  65. m_pColorPointer[newIdx2+7] = op;
  66. }
  67. }
  68. //当前的顶点数量减去完全消隐的顶点数量。
  69. m_uNuPoints-=mov;
  70. //响应菜单按钮项进行下一个演示。
  71. void nextCallback(CCObject* pSender);
  72. //响应菜单按钮项进行上一个演示。
  73. void backCallback(CCObject* pSender);
  74. //响应菜单文字项进行模式切换。
  75. void modeCallback(CCObject* pSender);
  76. protected:
  77. //拖尾对象指针。
  78. CCMotionStreak *streak;
  79. };

对应CPP:

[cpp] view plaincopy

  1. //枚举所用到的精灵的TAG值
  2. enum {
  3. kTagLabel = 1,
  4. kTagSprite1 = 2,
  5. kTagSprite2 = 3,
  6. };
  7. //下一个效果演示
  8. CCLayer* nextMotionAction();
  9. //上一个效果演示
  10. CCLayer* backMotionAction();
  11. //重新演示当前的效果
  12. CCLayer* restartMotionAction();
  13. //场景索引
  14. static int sceneIdx = -1;
  15. //最大层数
  16. #define MAX_LAYER    3
  17. //根据效果创建不同的拖尾效果
  18. CCLayer* createMotionLayer(int nIndex)
  19. {
  20. switch(nIndex)
  21. {
  22. case 0: return new MotionStreakTest1();
  23. case 1: return new MotionStreakTest2();
  24. case 2: return new Issue1358();
  25. }
  26. return NULL;
  27. }
  28. //下一个效果
  29. CCLayer* nextMotionAction()
  30. {
  31. sceneIdx++;
  32. sceneIdx = sceneIdx % MAX_LAYER;
  33. CCLayer* pLayer = createMotionLayer(sceneIdx);
  34. pLayer->autorelease();
  35. return pLayer;
  36. }
  37. //上一个效果演示
  38. CCLayer* backMotionAction()
  39. {
  40. sceneIdx—;
  41. int total = MAX_LAYER;
  42. if( sceneIdx < 0 )
  43. sceneIdx += total;
  44. CCLayer* pLayer = createMotionLayer(sceneIdx);
  45. pLayer->autorelease();
  46. return pLayer;
  47. }
  48. //重新演示当前的效果
  49. CCLayer* restartMotionAction()
  50. {
  51. CCLayer* pLayer = createMotionLayer(sceneIdx);
  52. pLayer->autorelease();
  53. return pLayer;
  54. }
  55. //构造
  56. MotionStreakTest::MotionStreakTest(void)
  57. {
  58. }
  59. //析构
  60. MotionStreakTest::~MotionStreakTest(void)
  61. {
  62. }
  63. //标题
  64. std::string MotionStreakTest::title()
  65. {
  66. return “No title”;
  67. }
  68. //副标题。
  69. std::string MotionStreakTest::subtitle()
  70. {
  71. return “”;
  72. }
  73. //当前层加载时的处理
  74. void MotionStreakTest::onEnter()
  75. {
  76. //调用基类的相应处理。
  77. CCLayer::onEnter();
  78. //获取屏幕大小
  79. CCSize s = CCDirector::sharedDirector()->getWinSize();
  80. //创建标题文字标签
  81. CCLabelTTF* label = CCLabelTTF::create(title().c_str(), “Arial”, 32);
  82. //将文字标签加入当前层中
  83. addChild(label, 0, kTagLabel);
  84. //设置文字标签的位置
  85. label->setPosition(CCPointMake(s.width/2, s.height-50));
  86. //取得副标题
  87. string subTitle = this->subtitle();
  88. //创建副标题文字标签
  89. if (subTitle.size() > 0)
  90. {
  91. CCLabelTTF *l = CCLabelTTF::create(subTitle.c_str(), “Thonburi”, 16);
  92. addChild(l, 1);
  93. l->setPosition(ccp(s.width/2, s.height-80));
  94. }
  95. //创建菜单项
  96. CCMenuItemImage *item1 = CCMenuItemImage::create(s_pPathB1, s_pPathB2, this, menu_selector(MotionStreakTest::backCallback) );
  97. CCMenuItemImage *item2 = CCMenuItemImage::create(s_pPathR1, s_pPathR2, this, menu_selector(MotionStreakTest::restartCallback) );
  98. CCMenuItemImage *item3 = CCMenuItemImage::create(s_pPathF1, s_pPathF2, this, menu_selector(MotionStreakTest::nextCallback) );
  99. //创建菜单
  100. CCMenu *menu = CCMenu::create(item1, item2, item3, NULL);
  101. //设置菜单与各菜单项的位置
  102. menu->setPosition(CCPointZero);
  103. item1->setPosition(CCPointMake(s.width/2 - item2->getContentSize().width*2, item2->getContentSize().height/2));
  104. item2->setPosition(CCPointMake(s.width/2, item2->getContentSize().height/2));
  105. item3->setPosition(CCPointMake(s.width/2 + item2->getContentSize().width*2, item2->getContentSize().height/2));
  106. //将菜单加入当前层
  107. addChild(menu, 1);
  108. //创建一个菜单切换文字项,其实就是有复选框效果的文字标签。这里创建的切换项为“质量优先模式”和“效率优先模式”,响应函数为modeCallback。
  109. CCMenuItemToggle *itemMode = CCMenuItemToggle::createWithTarget(this, menu_selector(MotionStreakTest::modeCallback),
  110. CCMenuItemFont::create(“Use High Quality Mode”),
  111. CCMenuItemFont::create(“Use Fast Mode”),
  112. NULL);
  113. //创建第二个菜单并加入当前层
  114. CCMenu *menuMode = CCMenu::create(itemMode, NULL);
  115. addChild(menuMode);
  116. //设置菜单位置
  117. menuMode->setPosition(ccp(s.width/2, s.height/4));
  118. }
  119. //切换文字项的响应函数。
  120. void MotionStreakTest::modeCallback(CCObject *pSender)
  121. {
  122. //来回切换模式
  123. bool fastMode = streak->isFastMode();
  124. streak->setFastMode(! fastMode);
  125. }
  126. //重新演示当前效果。
  127. void MotionStreakTest::restartCallback(CCObject* pSender)
  128. {
  129. //创建一个演示场景。
  130. CCScene* s = new MotionStreakTestScene();//CCScene::create();
  131. s->addChild(restartMotionAction());
  132. //使用当前场景。
  133. CCDirector::sharedDirector()->replaceScene(s);
  134. s->release();
  135. }
  136. //下一个效果的演示
  137. void MotionStreakTest::nextCallback(CCObject* pSender)
  138. {
  139. //创建一个演示场景。
  140. CCScene* s = new MotionStreakTestScene();//CCScene::create();
  141. //将下一个演示层加入场景,并运行这个场景
  142. s->addChild( nextMotionAction() );
  143. CCDirector::sharedDirector()->replaceScene(s);
  144. s->release();
  145. }
  146. //上一个效果的演示
  147. void MotionStreakTest::backCallback(CCObject* pSender)
  148. {   //创建一个演示场景。
  149. CCScene* s = new MotionStreakTestScene;//CCScene::create();
  150. //将上一个演示层加入场景,并运行这个场景
  151. s->addChild( backMotionAction() );
  152. CCDirector::sharedDirector()->replaceScene(s);
  153. s->release();
  154. }

然后是派生的第一个拖尾效果演示类:

[cpp] view plaincopy

  1. class MotionStreakTest1 : public MotionStreakTest
  2. {
  3. protected:
  4. //根结点
  5. CCNode*        m_root;
  6. //带拖尾的目标结点
  7. CCNode*        m_target;
  8. public:
  9. //加载当前层时的处理
  10. virtual void onEnter();
  11. //更新函数
  12. void onUpdate(float delta);
  13. //取得标题
  14. virtual std::string title();
  15. };

对应CPP:

[cpp] view plaincopy

  1. //加载当前层时的处理
  2. void MotionStreakTest1::onEnter()
  3. {
  4. //调用基类的相应函数。
  5. MotionStreakTest::onEnter();
  6. //取和屏幕大小
  7. CCSize s = CCDirector::sharedDirector()->getWinSize();
  8. // 创建根精灵结点,放入当前层中的屏幕中心位置。
  9. m_root = CCSprite::create(s_pPathR1);
  10. addChild(m_root, 1);
  11. m_root->setPosition(ccp(s.width/2, s.height/2));
  12. //创建目标精灵结点,放入根结点下的右边1/4屏幕宽度位置。
  13. m_target = CCSprite::create(s_pPathR1);
  14. m_root->addChild(m_target);
  15. m_target->setPosition(ccp(s.width/4, 0));
  16. // 创建拖尾效果并放入到当前层下。
  17. streak = CCMotionStreak::create(2, 3, 32, ccGREEN, s_streak);
  18. addChild(streak);
  19. //每帧调用onUpdate函数。
  20. schedule(schedule_selector(MotionStreakTest1::onUpdate));
  21. //创建一个旋转动画,2秒内自转360度。
  22. CCActionInterval* a1 = CCRotateBy::create(2, 360);
  23. //创建一个al1的无限循环动画。
  24. CCAction* action1 = CCRepeatForever::create(a1);
  25. //创建一个平移动画,2秒内向右移动100像素。
  26. CCActionInterval* motion = CCMoveBy::create(2, CCPointMake(100,0) );
  27. //根结点运行一个无限循环的动画序列,动画序列为平移动画及其反向动画。     m_root->runAction( CCRepeatForever::create((CCActionInterval*)(CCSequence::create(motion, motion->reverse(), NULL)) ) );
  28. //同时也运行无限循环的自转动画。
  29. m_root->runAction( action1 );
  30. //创建一个无限循环的动画序列,动画序列为7个变色动画,哪个结点使用它就会不断的变色。
  31. CCActionInterval *colorAction = CCRepeatForever::create((CCActionInterval *)CCSequence::create(
  32. CCTintTo::create(0.2f, 255, 0, 0),
  33. CCTintTo::create(0.2f, 0, 255, 0),
  34. CCTintTo::create(0.2f, 0, 0, 255),
  35. CCTintTo::create(0.2f, 0, 255, 255),
  36. CCTintTo::create(0.2f, 255, 255, 0),
  37. CCTintTo::create(0.2f, 255, 0, 255),
  38. CCTintTo::create(0.2f, 255, 255, 255),
  39. NULL));
  40. //让拖尾运行这个变色动画序列。
  41. streak->runAction(colorAction);
  42. }
  43. //实时更新函数。
  44. void MotionStreakTest1::onUpdate(float delta)
  45. {
  46. //更新拖尾的位置,设置为目标精灵结点的位置。
  47. streak->setPosition( m_target->convertToWorldSpace(CCPointZero) );
  48. }
  49. //取得标题。
  50. std::string MotionStreakTest1::title()
  51. {
  52. return “MotionStreak test 1”;
  53. }

演示如图:

【转】Cocos2d-x 2.0 拖尾效果深入分析

派生的第二个拖尾效果演示类:

[cpp] view plaincopy

  1. class MotionStreakTest2 : public MotionStreakTest
  2. {
  3. //根结点
  4. CCNode*        m_root;
  5. //带拖尾的目标结点
  6. CCNode*        m_target;
  7. public:
  8. //加载当前层时的处理
  9. virtual void onEnter();
  10. //触屏并移动时响应处理
  11. void ccTouchesMoved(CCSet* touches, CCEvent* event);
  12. //取得标题
  13. virtual std::string title();
  14. };

对应的CPP:

[cpp] view plaincopy

  1. //加载当前层时的处理
  2. void MotionStreakTest2::onEnter()
  3. {
  4. //调用基类的相应函数。
  5. MotionStreakTest::onEnter();
  6. //这里设置打开触屏响应
  7. setTouchEnabled(true);
  8. //取得屏幕大小
  9. CCSize s = CCDirector::sharedDirector()->getWinSize();
  10. // 创建拖尾效果并放入到当前层下。
  11. streak = CCMotionStreak::create(3, 3, 64, ccWHITE, s_streak );
  12. addChild(streak);
  13. //设置拖尾的初始位置为屏幕中小。
  14. streak->setPosition( CCPointMake(s.width/2, s.height/2) );
  15. }
  16. //触屏并移动时响应处理
  17. void MotionStreakTest2::ccTouchesMoved(CCSet* touches, CCEvent* event)
  18. {
  19. //取得触点位置。
  20. CCSetIterator it = touches->begin();
  21. CCTouch* touch = (CCTouch*)(*it);
  22. CCPoint touchLocation = touch->getLocation();
  23. //设置为拖层的位置。
  24. streak->setPosition( touchLocation );
  25. }
  26. //取得标题
  27. std::string MotionStreakTest2::title()
  28. {
  29. return “MotionStreak test”;
  30. }

效果如图:

【转】Cocos2d-x 2.0 拖尾效果深入分析

派生的第三个拖尾效果演示类:

[cpp] view plaincopy

  1. class Issue1358 : public MotionStreakTest
  2. {
  3. public:
  4. //取得标题
  5. virtual std::string title();
  6. //取得副标题
  7. virtual std::string subtitle();
  8. //加载当前层时的处理
  9. virtual void onEnter();
  10. //更新函数
  11. virtual void update(float dt);
  12. private:
  13. //中心位置
  14. CCPoint m_center;
  15. //半径
  16. float m_fRadius;
  17. //角度
  18. float m_fAngle;
  19. };

对应CPP:

[cpp] view plaincopy

  1. //加载当前层时的处理
  2. void Issue1358::onEnter()
  3. {
  4. //调用基类的相应函数。
  5. MotionStreakTest::onEnter();
  6. //取得屏幕位置
  7. CCSize size = CCDirector::sharedDirector()->getWinSize();
  8. // 创建拖尾效果并放入到当前层下。
  9. streak = CCMotionStreak::create(2.0f, 1.0f, 50.0f, ccc3(255, 255, 0), “Images/Icon.png”);
  10. addChild(streak);
  11. //初始化中心位置,半径和角度。
  12. m_center = ccp(size.width/2, size.height/2);
  13. m_fRadius = size.width/3;
  14. m_fAngle = 0.0f;
  15. //设置每帧的回调更新函数。
  16. schedule(schedule_selector(Issue1358::update), 0);
  17. }
  18. //每帧的回调更新函数。
  19. void Issue1358::update(float dt)
  20. {
  21. //角度增加1.0f
  22. m_fAngle += 1.0f;
  23. //计算拖尾的位置
  24. streak->setPosition(ccp(m_center.x + cosf(m_fAngle/180 * M_PI)*m_fRadius,
  25. m_center.y + sinf(m_fAngle/ 180 * M_PI)*m_fRadius));
  26. }
  27. //取得标题。
  28. std::string Issue1358::title()
  29. {
  30. return “Issue 1358”;
  31. }
  32. //取得副标题。
  33. std::string Issue1358::subtitle()
  34. {
  35. return “The tail should use the texture”;
  36. }

效果如图:

【转】Cocos2d-x 2.0 拖尾效果深入分析

然后是演示用的场景:

[cpp] view plaincopy

  1. class MotionStreakTestScene : public TestScene
  2. {
  3. public:
  4. //运行场景的处理
  5. virtual void runThisTest();
  6. };
  7. //运行场景的处理
  8. void MotionStreakTestScene::runThisTest()
  9. {
  10. //创建下一个要演示的效果并放入当前场景中。
  11. CCLayer* pLayer = nextMotionAction();
  12. addChild(pLayer);
  13. //使用当前场景。
  14. CCDirector::sharedDirector()->replaceScene(this);
  15. }

总结一下:

拖尾效果的原理就是在相应距离内动态生成条带,然后逐渐消隐,在Cocos2d-x中可以指定这个最小距离,以及消隐的速度,还有条带的粗细,相应的纹理对象,都是通过CCMotionStreak 类来实现的。

又一篇结束了,看看时间,一点半了,为了今年的目标,我只能坚持下去。工作,写作,工具箱,一个都不能少!努力吧,骚年!