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


    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中,拖尾效果有一个专门的类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. }

    演示如图:

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

    [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. }

    效果如图:

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

    [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. }

    效果如图:

    然后是演示用的场景:

    [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 类来实现的。

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

  • 相关阅读:
    [luogu] P1440 求m区间内的最小值
    [NOI2014]起床困难综合症
    [SDOI2009]地图复原
    [USACO08JAN] Cow Contest
    【洛谷P5049】旅行(数据加强版)
    【NOIP2015】真题回顾
    【NOIP2014】真题回顾
    【UVA11987】Almost Union-Find
    【UVA11988】破损的键盘
    【UVA11134】传说中的车
  • 原文地址:https://www.cnblogs.com/yssgyw/p/3280899.html
Copyright © 2020-2023  润新知