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

2024-06-02 07:08

本文主要是介绍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 plain copy
  1. #ifndef __CCMOTION_STREAK_H__  
  2. #define __CCMOTION_STREAK_H__  
  3.   
  4. #include "CCProtocols.h"  
  5. #include "textures/CCTexture2D.h"  
  6. #include "ccTypes.h"  
  7. #include "base_nodes/CCNode.h"  
  8. //使用Cocos2d命名空间  
  9. NS_CC_BEGIN  
  10.   
  11. //条带由三个基类共同派生  
  12. class CC_DLL CCMotionStreak : public CCNode, public CCTextureProtocol, public CCRGBAProtocol  
  13. {  
  14. public:  
  15.     //构造  
  16.     CCMotionStreak();  
  17.     //析构  
  18.     virtual ~CCMotionStreak();  
  19.     //静态函数,创建一个拖尾效果,内部调用create实现,参一为消隐动画时长,参二为拖尾条带相邻顶点间的最小距离,参三为拖尾条带的宽度,参四为顶点颜色值,参五为所使用的纹理图片。  
  20.     CC_DEPRECATED_ATTRIBUTE static CCMotionStreak* streakWithFade(float fade, float minSeg, float stroke, ccColor3B color, const char* path);  
  21.     //静态函数,创建一个拖尾效果,内部调用create实现,参一为消隐动画时长,参二为拖尾条带相邻顶点间的最小距离,参三为拖尾条带的宽度,参四为顶点颜色值,参五为所使用的纹理对象指针。  
  22.     CC_DEPRECATED_ATTRIBUTE static CCMotionStreak* streakWithFade(float fade, float minSeg, float stroke, ccColor3B color, CCTexture2D* texture);  
  23.   
  24.     //上面第一个创建函数的create实现。  
  25.     static CCMotionStreak* create(float fade, float minSeg, float stroke, ccColor3B color, const char* path);  
  26.     //上面第二个创建函数的create实现。  
  27.     static CCMotionStreak* create(float fade, float minSeg, float stroke, ccColor3B color, CCTexture2D* texture);  
  28.   
  29.     //初始化拖尾效果  
  30.     bool initWithFade(float fade, float minSeg, float stroke, ccColor3B color, const char* path);  
  31.     //初始化拖尾效果  
  32.     bool initWithFade(float fade, float minSeg, float stroke, ccColor3B color, CCTexture2D* texture);  
  33.   
  34.     //  
  35.     void tintWithColor(ccColor3B colors);  
  36.   
  37.     //重置,删除所有的条带段  
  38.     void reset();  
  39.   
  40.     //设置位置  
  41.     virtual void setPosition(const CCPoint& position);  
  42.     //绘制  
  43.     virtual void draw();  
  44.     //更新  
  45.     virtual void update(float delta);  
  46.   
  47.     //取得纹理。  
  48.     virtual CCTexture2D* getTexture(void);  
  49.     //设置纹理。  
  50.     virtual void setTexture(CCTexture2D *texture);  
  51.     //设置  
  52.     virtual void setBlendFunc(ccBlendFunc blendFunc);  
  53.     virtual ccBlendFunc getBlendFunc(void);  
  54.     //设置颜色  
  55.     virtual void setColor(const ccColor3B& color);  
  56.     virtual const ccColor3B& getColor(void);  
  57.     //设置透明度  
  58.     virtual GLubyte getOpacity(void);  
  59.     virtual void setOpacity(GLubyte opacity);  
  60.     //设置修改A同时影响RGB  
  61.     virtual void setOpacityModifyRGB(bool bValue);  
  62.     virtual bool isOpacityModifyRGB(void);  
  63.   
  64.     //是否是快速模式  
  65.     inline bool isFastMode() { return m_bFastMode; }  
  66.     inline void setFastMode(bool bFastMode) { m_bFastMode = bFastMode; }  
  67.     //起点是否初始化  
  68.     inline bool isStartingPositionInitialized() { return m_bStartingPositionInitialized; }  
  69.     inline void setStartingPositionInitialized(bool bStartingPositionInitialized)   
  70.     {   
  71.         m_bStartingPositionInitialized = bStartingPositionInitialized;   
  72.     }  
  73. protected:  
  74.     //是否是快速模式  
  75.     bool m_bFastMode;  
  76.     //起点是否初始化  
  77.     bool m_bStartingPositionInitialized;  
  78. private:  
  79.     //所用的纹理对象指针  
  80.     CCTexture2D* m_pTexture;  
  81.     //ALPHA混合方案  
  82.     ccBlendFunc m_tBlendFunc;  
  83.     //当前拖尾起点位置  
  84.     CCPoint m_tPositionR;  
  85.     //颜色值  
  86.     ccColor3B m_tColor;  
  87.     //拖尾线条的宽度,越大当前越粗  
  88.     float m_fStroke;  
  89.     //每秒条带渐隐的alpha值减少量  
  90.     float m_fFadeDelta;  
  91.     //拖尾中用于划分条带的顶点的最小距离。  
  92.     float m_fMinSeg;  
  93.     //顶点最大数量  
  94.     unsigned int m_uMaxPoints;  
  95.     //当前的顶点数量  
  96.     unsigned int m_uNuPoints;  
  97.     //上次的顶点数量  
  98.     unsigned int m_uPreviousNuPoints;  
  99.   
  100.     //顶点位置数组  
  101.     CCPoint* m_pPointVertexes;  
  102.     //顶点的状态值数组,这个状态值取值为0~1.0间,代表了消隐程度,其实就是alpha值。  
  103.     float* m_pPointState;  
  104.   
  105.     // OPENGL所用的顶点各类数据绘冲  
  106.     //位置  
  107.     ccVertex2F* m_pVertices;  
  108.     //颜色  
  109.     GLubyte* m_pColorPointer;  
  110.     //纹理UV  
  111.     ccTex2F* m_pTexCoords;  
  112. };  
  113.   
  114. // end of misc_nodes group  
  115. /// @}  
  116.   
  117. NS_CC_END  
  118.   
  119. #endif //__CCMOTION_STREAK_H__  

对应的CPP:

[cpp] view plain copy
  1. #include "CCMotionStreak.h"  
  2. #include "textures/CCTextureCache.h"  
  3. #include "shaders/ccGLStateCache.h"  
  4. #include "shaders/CCGLProgram.h"  
  5. #include "shaders/CCShaderCache.h"  
  6. #include "ccMacros.h"  
  7.   
  8. #include "support/CCVertex.h"  
  9. #include "support/CCPointExtension.h"  
  10. //使用Cocos2d命名空间  
  11. NS_CC_BEGIN  
  12. //构造  
  13. CCMotionStreak::CCMotionStreak()  
  14. : m_bFastMode(false)  
  15. , m_pTexture(NULL)  
  16. , m_tPositionR(CCPointZero)  
  17. , m_tColor(ccc3(0,0,0))  
  18. , m_fStroke(0.0f)  
  19. , m_fFadeDelta(0.0f)  
  20. , m_fMinSeg(0.0f)  
  21. , m_uMaxPoints(0)  
  22. , m_uNuPoints(0)  
  23. , m_uPreviousNuPoints(0)  
  24. , m_pPointVertexes(NULL)  
  25. , m_pPointState(NULL)  
  26. , m_pVertices(NULL)  
  27. , m_pColorPointer(NULL)  
  28. , m_pTexCoords(NULL)  
  29. , m_bStartingPositionInitialized(false)  
  30. {  
  31.     m_tBlendFunc.src = GL_SRC_ALPHA;  
  32.     m_tBlendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;  
  33. }  
  34. //析构  
  35. CCMotionStreak::~CCMotionStreak()  
  36. {  
  37.     //释放纹理对象和申请的内存缓冲区  
  38.     CC_SAFE_RELEASE(m_pTexture);  
  39.     CC_SAFE_FREE(m_pPointState);  
  40.     CC_SAFE_FREE(m_pPointVertexes);  
  41.     CC_SAFE_FREE(m_pVertices);  
  42.     CC_SAFE_FREE(m_pColorPointer);  
  43.     CC_SAFE_FREE(m_pTexCoords);  
  44. }  
  45. //静态函数,创建一个拖尾效果,内部调用create实现,参一为消隐动画时长,参二为拖尾条带相邻顶点间的最小距离,参三为拖尾条带的宽度,参四为顶点颜色值,参五为所使用的纹理图片。  
  46. CCMotionStreak* CCMotionStreak::streakWithFade(float fade, float minSeg, float stroke, ccColor3B color, const char* path)  
  47. {  
  48.     return CCMotionStreak::create(fade, minSeg, stroke, color, path);  
  49. }  
  50. //上面的create实现。   
  51. CCMotionStreak* CCMotionStreak::create(float fade, float minSeg, float stroke, ccColor3B color, const char* path)  
  52. {  
  53.     //创建一个CCMotionStreak的实例对象并初始化,如果成功交由内存管理器进行引用计数器的管理。  
  54.     CCMotionStreak *pRet = new CCMotionStreak();  
  55.     if (pRet && pRet->initWithFade(fade, minSeg, stroke, color, path))  
  56.     {  
  57.         pRet->autorelease();  
  58.         return pRet;  
  59.     }  
  60.     //如果创建或初始化失败,删除实例对象指针并置空,返回NULL。  
  61.     CC_SAFE_DELETE(pRet);  
  62.     return NULL;  
  63. }  
  64. //静态函数,创建一个拖尾效果,内部调用create实现,参一为消隐动画时长,参二为拖尾条带相邻顶点间的最小距离,参三为拖尾条带的宽度,参四为顶点颜色值,参五为所使用的纹理对象。  
  65. CCMotionStreak* CCMotionStreak::streakWithFade(float fade, float minSeg, float stroke, ccColor3B color, CCTexture2D* texture)  
  66. {  
  67.     return CCMotionStreak::create(fade, minSeg, stroke, color, texture);  
  68. }  
  69. //上面创建函数的create实现。  
  70. CCMotionStreak* CCMotionStreak::create(float fade, float minSeg, float stroke, ccColor3B color, CCTexture2D* texture)  
  71. {  
  72.     //创建一个CCMotionStreak的实例对象并初始化,如果成功交由内存管理器进行引用计数器的管理。  
  73.     CCMotionStreak *pRet = new CCMotionStreak();  
  74.     if (pRet && pRet->initWithFade(fade, minSeg, stroke, color, texture))  
  75.     {  
  76.         pRet->autorelease();  
  77.         return pRet;  
  78.     }  
  79.     //如果创建或初始化失败,删除实例对象指针并置空,返回NULL。  
  80.     CC_SAFE_DELETE(pRet);  
  81.     return NULL;  
  82. }  
  83. //初始化条带  
  84. bool CCMotionStreak::initWithFade(float fade, float minSeg, float stroke, ccColor3B color, const char* path)  
  85. {  
  86.     //有效性判断。  
  87.     CCAssert(path != NULL, "Invalid filename");  
  88.     //加载图片生成纹理,使用纹理指针调用相应的初始化函数。  
  89.     CCTexture2D *texture = CCTextureCache::sharedTextureCache()->addImage(path);  
  90.     return initWithFade(fade, minSeg, stroke, color, texture);  
  91. }  
  92. //初始化条带  
  93. bool CCMotionStreak::initWithFade(float fade, float minSeg, float stroke, ccColor3B color, CCTexture2D* texture)  
  94. {  
  95.     //将结点位置为零零点。  
  96.     CCNode::setPosition(CCPointZero);  
  97.     //设置锚点位置为零零点。  
  98.     setAnchorPoint(CCPointZero);  
  99.     //  
  100.     ignoreAnchorPointForPosition(true);  
  101.     //  
  102.     m_bStartingPositionInitialized = false;  
  103.     //初始化起点为零零点。  
  104.     m_tPositionR = CCPointZero;  
  105.     //使用快速模式  
  106.     m_bFastMode = true;  
  107.     //如果minSeg值设-1,则成员变量m_fMinSeg取默认值为宽度/5.0f,否则按照参数取值。  
  108.     m_fMinSeg = (minSeg == -1.0f) ? stroke/5.0f : minSeg;  
  109.     //为什么要乘积呢?因为后面判断距离时提高效率,两点间距离公式不是要开平方嘛?这样做就省掉开平方了。  
  110.     m_fMinSeg *= m_fMinSeg;  
  111.     //保存拖尾效果条带的宽度。  
  112.     m_fStroke = stroke;  
  113.     //计算出每秒条带渐隐的alpha值减少量  
  114.     m_fFadeDelta = 1.0f/fade;  
  115.     //顶点最大数量这里是按消隐动画时长来计算的,每秒60个顶点,再加上首尾两个顶点。  
  116.     m_uMaxPoints = (int)(fade*60.0f)+2;  
  117.     //当前顶点数量为0。  
  118.     m_uNuPoints = 0;  
  119.     //创建相应顶点数量的状态值数组和顶点位置数组。  
  120.     m_pPointState = (float *)malloc(sizeof(float) * m_uMaxPoints);  
  121.     m_pPointVertexes = (CCPoint*)malloc(sizeof(CCPoint) * m_uMaxPoints);  
  122.     //创建相应顶点缓冲所用的内存。  
  123.     m_pVertices = (ccVertex2F*)malloc(sizeof(ccVertex2F) * m_uMaxPoints * 2);  
  124.     m_pTexCoords = (ccTex2F*)malloc(sizeof(ccTex2F) * m_uMaxPoints * 2);  
  125.     m_pColorPointer =  (GLubyte*)malloc(sizeof(GLubyte) * m_uMaxPoints * 2 * 4);  
  126.   
  127.     // 设置ALPHA混合方案  
  128.     m_tBlendFunc.src = GL_SRC_ALPHA;  
  129.     m_tBlendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;  
  130.   
  131.     // 设置所用的Shader代码片段  
  132. setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTextureColor));  
  133.   
  134.     //设置所用的纹理  
  135.     setTexture(texture);  
  136.     //设置所用的颜色  
  137.     setColor(color);  
  138.     //  
  139.     scheduleUpdate();  
  140.   
  141.     return true;  
  142. }  
  143. //设置位置  
  144. void CCMotionStreak::setPosition(const CCPoint& position)  
  145. {  
  146.     m_bStartingPositionInitialized = true;  
  147.     m_tPositionR = position;  
  148. }  
  149. //设置颜色  
  150. void CCMotionStreak::tintWithColor(ccColor3B colors)  
  151. {  
  152.     //  
  153.     setColor(colors);  
  154.   
  155.     // Fast assignation  
  156.     for(unsigned int i = 0; i<m_uNuPoints*2; i++)   
  157.     {  
  158.         *((ccColor3B*) (m_pColorPointer+i*4)) = colors;  
  159.     }  
  160. }  
  161. //取得纹理  
  162. CCTexture2D* CCMotionStreak::getTexture(void)  
  163. {  
  164.     return m_pTexture;  
  165. }  
  166. //设置纹理  
  167. void CCMotionStreak::setTexture(CCTexture2D *texture)  
  168. {  
  169.     if (m_pTexture != texture)  
  170.     {  
  171.         CC_SAFE_RETAIN(texture);  
  172.         CC_SAFE_RELEASE(m_pTexture);  
  173.         m_pTexture = texture;  
  174.     }  
  175. }  
  176. //设置ALPHA混合方案  
  177. void CCMotionStreak::setBlendFunc(ccBlendFunc blendFunc)  
  178. {  
  179.     m_tBlendFunc = blendFunc;  
  180. }  
  181. //取得ALPHA混合方案。  
  182. ccBlendFunc CCMotionStreak::getBlendFunc(void)  
  183. {  
  184.     return m_tBlendFunc;  
  185. }  
  186. //设置颜色  
  187. void CCMotionStreak::setColor(const ccColor3B& color)  
  188. {  
  189.     m_tColor = color;  
  190. }  
  191. //取得颜色  
  192. const ccColor3B& CCMotionStreak::getColor(void)  
  193. {  
  194.     return m_tColor;  
  195. }  
  196. //设置透明度  
  197. void CCMotionStreak::setOpacity(GLubyte opacity)  
  198. {  
  199.     CCAssert(false"Set opacity no supported");  
  200. }  
  201. //取得透明度  
  202. GLubyte CCMotionStreak::getOpacity(void)  
  203. {  
  204.     CCAssert(false"Opacity no supported");  
  205.     return 0;  
  206. }  
  207. //设置修改透明度是否影响RGB值。  
  208. void CCMotionStreak::setOpacityModifyRGB(bool bValue)  
  209. {  
  210.     CC_UNUSED_PARAM(bValue);  
  211. }  
  212.   
  213. bool CCMotionStreak::isOpacityModifyRGB(void)  
  214. {  
  215.     return false;  
  216. }  
  217. //更新处理  
  218. void CCMotionStreak::update(float delta)  
  219. {  
  220.     //如果未初始化直接返回。  
  221.     if (!m_bStartingPositionInitialized)  
  222.     {  
  223.         return;  
  224.     }  
  225.     //通过时间音隔x每秒消隐值,取得当前时间片内要消隐的值。  
  226.     delta *= m_fFadeDelta;  
  227.     //定义临时变量  
  228.     unsigned int newIdx, newIdx2, i, i2;  
  229.     //定义临时变量保存消隐的顶点个数。  
  230.     unsigned int mov = 0;  
  231.   
  232.     // 遍历更新当前所有的顶点。  
  233.     for(i = 0; i<m_uNuPoints; i++)  
  234.     {  
  235.         //状态数组对应值减去消隐值。  
  236.         m_pPointState[i]-=delta;  
  237.         //如果小于0,即完全消隐,mov++。  
  238.         if(m_pPointState[i] <= 0)  
  239.             mov++;  
  240.         else  
  241.         {  
  242.             //这里是通过mov计算出当前顶点数组在更新后移除完全消隐的顶点之后的当前顶点实际位置保存到变量newIdx。  
  243.             newIdx = i-mov;  
  244.             //如果mov大于0,即有完全消隐的顶点。  
  245.             if(mov>0)  
  246.             {  
  247.                 // 将当前顶点原来的状态值保存到数组新位置中,这是一个前移操作。  
  248.                 m_pPointState[newIdx] = m_pPointState[i];  
  249.   
  250.                 //将当前顶点原来的位置值保存到数组新位置中。  
  251.                 m_pPointVertexes[newIdx] = m_pPointVertexes[i];  
  252.   
  253.                 //将当前顶点原来的位置顶点缓冲值保存到顶点缓冲新位置中。  
  254.                 i2 = i*2;  
  255.                 newIdx2 = newIdx*2;  
  256.                 m_pVertices[newIdx2] = m_pVertices[i2];  
  257.                 m_pVertices[newIdx2+1] = m_pVertices[i2+1];  
  258.   
  259.                 //将当前顶点原来的颜色顶点缓冲值保存到顶点缓冲新位置中。这里要注意,因为是GLubyte格式,所以A,R,G,B分别占一个数组元素。  
  260.                 i2 *= 4;  
  261.                 newIdx2 *= 4;  
  262.                 m_pColorPointer[newIdx2+0] = m_pColorPointer[i2+0];  
  263.                 m_pColorPointer[newIdx2+1] = m_pColorPointer[i2+1];  
  264.                 m_pColorPointer[newIdx2+2] = m_pColorPointer[i2+2];  
  265.                 m_pColorPointer[newIdx2+4] = m_pColorPointer[i2+4];  
  266.                 m_pColorPointer[newIdx2+5] = m_pColorPointer[i2+5];  
  267.                 m_pColorPointer[newIdx2+6] = m_pColorPointer[i2+6];  
  268.             }else  
  269.                 newIdx2 = newIdx*8;//如果mov等于0,则R,G,B值不用变,只修改A值即可。  
  270.             //将当前顶点原来的颜色顶点缓冲中Alpha值保存到顶点缓冲新位置Alpha值中。  
  271.             const GLubyte op = (GLubyte)(m_pPointState[newIdx] * 255.0f);  
  272.             m_pColorPointer[newIdx2+3] = op;  
  273.             m_pColorPointer[newIdx2+7] = op;  
  274.         }  
  275.     }  
  276.     //当前的顶点数量减去完全消隐的顶点数量。  
  277.     m_uNuPoints-=mov;  
  278.   
  279.     // 定义临时变量判断是否需要增加顶点。  
  280.     bool appendNewPoint = true;  
  281.     //如果当前顶点数量大于最大顶点数量,不能再新增顶点了。  
  282.     if(m_uNuPoints >= m_uMaxPoints)  
  283.     {  
  284.         appendNewPoint = false;  
  285.     }  
  286.     //如果当前顶点数量大于0,需要做一些计算来判断是否增加新顶点。  
  287.     else if(m_uNuPoints>0)  
  288.     {  
  289.         //取当前拖尾起点位置顶点与后面一个顶点的距离的平方,看是否小于m_fMinSeg。  
  290.         bool a1 = ccpDistanceSQ(m_pPointVertexes[m_uNuPoints-1], m_tPositionR) < m_fMinSeg;  
  291.         //取当前拖尾起点位置顶点与后面第二个顶点的距离的平方,看是否小于m_fMinSeg*2。  
  292.         bool a2 = (m_uNuPoints == 1) ? false : (ccpDistanceSQ(m_pPointVertexes[m_uNuPoints-2], m_tPositionR) < (m_fMinSeg * 2.0f));  
  293.         //如果在距离范围内,就不再增加顶点,这一段代码是为了避免拖尾间顶点过密过多,约定只有相邻顶点间距离达到一定范围以外才增加新的顶点。  
  294.         if(a1 || a2)  
  295.         {  
  296.             appendNewPoint = false;  
  297.         }  
  298.     }  
  299.     //如果需要增加新的顶点。  
  300.     if(appendNewPoint)  
  301.     {  
  302.         //将当前起点位置保存到相应数组元素中。  
  303.         m_pPointVertexes[m_uNuPoints] = m_tPositionR;  
  304.         //将相应状态数组元素值初始化为1.0。  
  305.         m_pPointState[m_uNuPoints] = 1.0f;  
  306.   
  307.         // 颜色赋值  
  308.         const unsigned int offset = m_uNuPoints*8;  
  309.         *((ccColor3B*)(m_pColorPointer + offset)) = m_tColor;  
  310.         *((ccColor3B*)(m_pColorPointer + offset+4)) = m_tColor;  
  311.   
  312.         // 透明度赋值  
  313.         m_pColorPointer[offset+3] = 255;  
  314.         m_pColorPointer[offset+7] = 255;  
  315.   
  316.         //生成相应的四边形条带  
  317.         if(m_uNuPoints > 0 && m_bFastMode )  
  318.         {  
  319.             if(m_uNuPoints > 1)  
  320.             {//如果当前顶点数量大于1,则由上一个顶点到当前顶点位置生成相四边形存入到m_pVertices。  
  321.                 ccVertexLineToPolygon(m_pPointVertexes, m_fStroke, m_pVertices, m_uNuPoints, 1);  
  322.             }  
  323.             else  
  324.             {//否则由起始位置到当前顶点位置生成相四边形存入到m_pVertices。  
  325.                 ccVertexLineToPolygon(m_pPointVertexes, m_fStroke, m_pVertices, 0, 2);  
  326.             }  
  327.         }  
  328.         //顶点数量加一。  
  329.         m_uNuPoints ++;  
  330.     }  
  331.     //如果不是快速模式,则从起始位置到当前顶点位置生成相应四边形条带存入到m_pVertices。可见,快速模式比非快速模式要生成更少的次数。  
  332.     if( ! m_bFastMode )  
  333.     {  
  334.         ccVertexLineToPolygon(m_pPointVertexes, m_fStroke, m_pVertices, 0, m_uNuPoints);  
  335.     }  
  336.   
  337.     // 更新纹理坐标  
  338.     if( m_uNuPoints  && m_uPreviousNuPoints != m_uNuPoints ) {  
  339.         float texDelta = 1.0f / m_uNuPoints;  
  340.         for( i=0; i < m_uNuPoints; i++ ) {  
  341.             //左右两边各一个顶点,故纹理U值分别为¬0,1  
  342.             m_pTexCoords[i*2] = tex2(0, texDelta*i);  
  343.             m_pTexCoords[i*2+1] = tex2(1, texDelta*i);  
  344.         }  
  345.         //记录当前粒子数量。  
  346.         m_uPreviousNuPoints = m_uNuPoints;  
  347.     }  
  348. }  
  349. //重置  
  350. void CCMotionStreak::reset()  
  351. {  
  352.     m_uNuPoints = 0;  
  353. }  
  354. //绘制  
  355. void CCMotionStreak::draw()  
  356. {  
  357.     //如果粒子数量<=1,不能形成条带,就不需要显示。  
  358.     if(m_uNuPoints <= 1)  
  359.         return;  
  360.     //设置使用shader,并设置相关矩阵。  
  361.     CC_NODE_DRAW_SETUP();  
  362.     //设置使用的顶点格式和ALPHA混合方案。  
  363.     ccGLEnableVertexAttribs(kCCVertexAttribFlag_PosColorTex );  
  364.     ccGLBlendFunc( m_tBlendFunc.src, m_tBlendFunc.dst );  
  365.     //设置使用的纹理。  
  366.     ccGLBindTexture2D( m_pTexture->getName() );  
  367.     //设置顶点缓冲区。  
  368.     glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, m_pVertices);  
  369.     glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, m_pTexCoords);  
  370.     glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, m_pColorPointer);  
  371.     //渲染三角形条带  
  372.     glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)m_uNuPoints*2);  
  373.     //更新渲染调用次数统计  
  374.     CC_INCREMENT_GL_DRAWS(1);  
  375. }  
  376.   
  377. NS_CC_END  

拖尾效果类的实现原理了解了,现在我们看一下Cocos2d-x中的相关演示。

MotionStreakTest.h:

[cpp] view plain copy
  1. #ifndef _MOTION_STREAK_TEST_H_  
  2. #define _MOTION_STREAK_TEST_H_  
  3.   
  4. #include "../testBasic.h"  
  5. //使用Cocos2d命名空间  
  6. //USING_NS_CC;  
  7. //用于演示的基类。  
  8. class MotionStreakTest : public CCLayer  
  9. {  
  10. public:  
  11.     //构造  
  12.     MotionStreakTest(void);  
  13.     //析构  
  14.     ~MotionStreakTest(void);  
  15.     //取得标题。  
  16.     virtual std::string title();  
  17.     //取得副标题。  
  18.     virtual std::string subtitle();  
  19.     //当前层被加载时的处理。  
  20.     virtual void onEnter();  
  21.     //响应菜单按钮项重启当前演示。  
  22.     void restartCallback(CCObject* pSender);  
  23.     //响应菜单按钮项进行下一个演示。  
  24.     void nextCallback(CCObject* pSender);  
  25.     //响应菜单按钮项进行上一个演示。  
  26.     void backCallback(CCObject* pSender);  
  27.     //响应菜单文字项进行模式切换。  
  28.     void modeCallback(CCObject* pSender);  
  29. protected:  
  30.     //拖尾对象指针。  
  31.     CCMotionStreak *streak;  
  32. };  

对应CPP:

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

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

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

对应CPP:

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



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

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

效果如图:



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

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

效果如图:



然后是演示用的场景:

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

      

总结一下:

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

这篇关于Cocos2d-x 2.0 拖尾效果深入分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1023283

相关文章

防近视护眼台灯什么牌子好?五款防近视效果好的护眼台灯推荐

在家里,灯具是属于离不开的家具,每个大大小小的地方都需要的照亮,所以一盏好灯是必不可少的,每个发挥着作用。而护眼台灯就起了一个保护眼睛,预防近视的作用。可以保护我们在学习,阅读的时候提供一个合适的光线环境,保护我们的眼睛。防近视护眼台灯什么牌子好?那我们怎么选择一个优秀的护眼台灯也是很重要,才能起到最大的护眼效果。下面五款防近视效果好的护眼台灯推荐: 一:六个推荐防近视效果好的护眼台灯的

【Godot4.3】多边形的斜线填充效果基础实现

概述 图案(Pattern)填充是一个非常常见的效果。其中又以斜线填充最为简单。本篇就探讨在Godot4.3中如何使用Geometry2D和CanvasItem的绘图函数实现斜线填充效果。 基础思路 Geometry2D类提供了多边形和多边形以及多边形与折线的布尔运算。按照自然的思路,多边形的斜线填充应该属于“多边形与折线的布尔运算”范畴。 第一个问题是如何获得斜线,这条斜线应该满足什么样

OpenGL ES 2.0渲染管线

http://codingnow.cn/opengles/1504.html Opengl es 2.0实现了可编程的图形管线,比起1.x的固定管线要复杂和灵活很多,由两部分规范组成:Opengl es 2.0 API规范和Opengl es着色语言规范。下图是Opengl es 2.0渲染管线,阴影部分是opengl es 2.0的可编程阶段。   1. 顶点着色器(Vert

UniApp实现漂亮的音乐歌词滚动播放效果

在现代的音乐播放应用中,歌词的展示和滚动播放已经成为了一个非常常见的功能。今天,我们将通过UniApp来实现一个漂亮的歌词滚动播放功能。我们将使用UniApp提供的组件和API来完成这个任务。 页面结构 在页面的模板部分,我们需要创建一个音频播放器和歌词展示区域。使用<scroll-view>组件来实现歌词的滚动效果。 <template><view class="audio-co

Nuxt3入门:过渡效果(第5节)

你好同学,我是沐爸,欢迎点赞、收藏、评论和关注。 Nuxt 利用 Vue 的 <Transition> 组件在页面和布局之间应用过渡效果。 一、页面过渡效果 你可以启用页面过渡效果,以便对所有页面应用自动过渡效果。 nuxt.config.js export default defineNuxtConfig({app: {pageTransition: {name: 'fade',mode

Differential Diffusion,赋予每个像素它应有的力量,以及在comfyui中的测试效果

🥽原论文要点 首先是原论文地址:https://differential-diffusion.github.io/paper.pdf 其次是git介绍地址:GitHub - exx8/differential-diffusion 感兴趣的朋友们可以自行阅读。 首先,论文开篇就给了一个例子: 我们的方法根据给定的图片和文本提示,以不同的程度改变图像的不同区域。这种可控性允许我们再现

【Unity小技巧】URP管线遮挡高亮效果

前言 在URP渲染管线环境下实现物体遮挡高亮显示效果,效果如下: Unity URP遮挡高亮 实现步骤 创建层级,为需要显示高亮效果的物体添加层级,比如Player 创建一个材质球,也就是高亮效果显示的材质球找到Universal Renderer Data Assets 4.在Assets上添加两个Render Objects组件 第一个做如下三处设置 指定遮挡层级指

海鲜加工污水处理设备处理效果高

诸城市鑫淼环保小编带大家了解一下海鲜加工污水处理设备处理效果高   海鲜加工污水处理设备通常采用物理、化学和生物处理相结合的方法,对废水中的污染物进行高xiao去除。设备设计紧凑,占地面积小,操作简便,适用于不同规模的海鲜加工厂。   设备特点   高xiao性:采用先进的处理工艺和技术,确保废水处理效果稳定可靠。   占地面积小:设备设计紧凑,占地面积小,适合在有限的空间内安装。

QT项目实战之音乐播放器2.0版本

该版本相较于1.0版本最主要的不同在于连接数据库实现类似于歌曲收藏和取消收藏的功能。 详细情况看我的这篇文章http://t.csdnimg.cn/WS5s8。 效果展示 VSMyMusicShow2.0 define.h UseMySQL.h   musicInfo.h   VSMyMusicPlayer.h