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
- #ifndef __CCMOTION_STREAK_H__
- #define __CCMOTION_STREAK_H__
- #include “CCProtocols.h”
- #include “textures/CCTexture2D.h”
- #include “ccTypes.h”
- #include “base_nodes/CCNode.h”
- //使用Cocos2d命名空间
- NS_CC_BEGIN
- //条带由三个基类共同派生
- class CC_DLL CCMotionStreak : public CCNode, public CCTextureProtocol, public CCRGBAProtocol
- {
- public:
- //构造
- CCMotionStreak();
- //析构
- virtual ~CCMotionStreak();
- //静态函数,创建一个拖尾效果,内部调用create实现,参一为消隐动画时长,参二为拖尾条带相邻顶点间的最小距离,参三为拖尾条带的宽度,参四为顶点颜色值,参五为所使用的纹理图片。
- CC_DEPRECATED_ATTRIBUTE static CCMotionStreak* streakWithFade(float fade, float minSeg, float stroke, ccColor3B color, const char* path);
- //静态函数,创建一个拖尾效果,内部调用create实现,参一为消隐动画时长,参二为拖尾条带相邻顶点间的最小距离,参三为拖尾条带的宽度,参四为顶点颜色值,参五为所使用的纹理对象指针。
- CC_DEPRECATED_ATTRIBUTE static CCMotionStreak* streakWithFade(float fade, float minSeg, float stroke, ccColor3B color, CCTexture2D* texture);
- //上面第一个创建函数的create实现。
- static CCMotionStreak* create(float fade, float minSeg, float stroke, ccColor3B color, const char* path);
- //上面第二个创建函数的create实现。
- static CCMotionStreak* create(float fade, float minSeg, float stroke, ccColor3B color, CCTexture2D* texture);
- //初始化拖尾效果
- bool initWithFade(float fade, float minSeg, float stroke, ccColor3B color, const char* path);
- //初始化拖尾效果
- bool initWithFade(float fade, float minSeg, float stroke, ccColor3B color, CCTexture2D* texture);
- //
- void tintWithColor(ccColor3B colors);
- //重置,删除所有的条带段
- void reset();
- //设置位置
- virtual void setPosition(const CCPoint& position);
- //绘制
- virtual void draw();
- //更新
- virtual void update(float delta);
- //取得纹理。
- virtual CCTexture2D* getTexture(void);
- //设置纹理。
- virtual void setTexture(CCTexture2D *texture);
- //设置
- virtual void setBlendFunc(ccBlendFunc blendFunc);
- virtual ccBlendFunc getBlendFunc(void);
- //设置颜色
- virtual void setColor(const ccColor3B& color);
- virtual const ccColor3B& getColor(void);
- //设置透明度
- virtual GLubyte getOpacity(void);
- virtual void setOpacity(GLubyte opacity);
- nbsp; i2 *= 4;
- newIdx2 *= 4;
- m_pColorPointer[newIdx2+0] = m_pColorPointer[i2+0];
- m_pColorPointer[newIdx2+1] = m_pColorPointer[i2+1];
- m_pColorPointer[newIdx2+2] = m_pColorPointer[i2+2];
- m_pColorPointer[newIdx2+4] = m_pColorPointer[i2+4];
- m_pColorPointer[newIdx2+5] = m_pColorPointer[i2+5];
- m_pColorPointer[newIdx2+6] = m_pColorPointer[i2+6];
- }else
- newIdx2 = newIdx*8;//如果mov等于0,则R,G,B值不用变,只修改A值即可。
- //将当前顶点原来的颜色顶点缓冲中Alpha值保存到顶点缓冲新位置Alpha值中。
- const GLubyte op = (GLubyte)(m_pPointState[newIdx] * 255.0f);
- m_pColorPointer[newIdx2+3] = op;
- m_pColorPointer[newIdx2+7] = op;
- }
- }
- //当前的顶点数量减去完全消隐的顶点数量。
- m_uNuPoints-=mov;
- //响应菜单按钮项进行下一个演示。
- void nextCallback(CCObject* pSender);
- //响应菜单按钮项进行上一个演示。
- void backCallback(CCObject* pSender);
- //响应菜单文字项进行模式切换。
- void modeCallback(CCObject* pSender);
- protected:
- //拖尾对象指针。
- CCMotionStreak *streak;
- };
对应CPP:
[cpp] view plaincopy
- //枚举所用到的精灵的TAG值
- enum {
- kTagLabel = 1,
- kTagSprite1 = 2,
- kTagSprite2 = 3,
- };
- //下一个效果演示
- CCLayer* nextMotionAction();
- //上一个效果演示
- CCLayer* backMotionAction();
- //重新演示当前的效果
- CCLayer* restartMotionAction();
- //场景索引
- static int sceneIdx = -1;
- //最大层数
- #define MAX_LAYER 3
- //根据效果创建不同的拖尾效果
- CCLayer* createMotionLayer(int nIndex)
- {
- switch(nIndex)
- {
- case 0: return new MotionStreakTest1();
- case 1: return new MotionStreakTest2();
- case 2: return new Issue1358();
- }
- return NULL;
- }
- //下一个效果
- CCLayer* nextMotionAction()
- {
- sceneIdx++;
- sceneIdx = sceneIdx % MAX_LAYER;
- CCLayer* pLayer = createMotionLayer(sceneIdx);
- pLayer->autorelease();
- return pLayer;
- }
- //上一个效果演示
- CCLayer* backMotionAction()
- {
- sceneIdx—;
- int total = MAX_LAYER;
- if( sceneIdx < 0 )
- sceneIdx += total;
- CCLayer* pLayer = createMotionLayer(sceneIdx);
- pLayer->autorelease();
- return pLayer;
- }
- //重新演示当前的效果
- CCLayer* restartMotionAction()
- {
- CCLayer* pLayer = createMotionLayer(sceneIdx);
- pLayer->autorelease();
- return pLayer;
- }
- //构造
- MotionStreakTest::MotionStreakTest(void)
- {
- }
- //析构
- MotionStreakTest::~MotionStreakTest(void)
- {
- }
- //标题
- std::string MotionStreakTest::title()
- {
- return “No title”;
- }
- //副标题。
- std::string MotionStreakTest::subtitle()
- {
- return “”;
- }
- //当前层加载时的处理
- void MotionStreakTest::onEnter()
- {
- //调用基类的相应处理。
- CCLayer::onEnter();
- //获取屏幕大小
- CCSize s = CCDirector::sharedDirector()->getWinSize();
- //创建标题文字标签
- CCLabelTTF* label = CCLabelTTF::create(title().c_str(), “Arial”, 32);
- //将文字标签加入当前层中
- addChild(label, 0, kTagLabel);
- //设置文字标签的位置
- label->setPosition(CCPointMake(s.width/2, s.height-50));
- //取得副标题
- string subTitle = this->subtitle();
- //创建副标题文字标签
- if (subTitle.size() > 0)
- {
- CCLabelTTF *l = CCLabelTTF::create(subTitle.c_str(), “Thonburi”, 16);
- addChild(l, 1);
- l->setPosition(ccp(s.width/2, s.height-80));
- }
- //创建菜单项
- CCMenuItemImage *item1 = CCMenuItemImage::create(s_pPathB1, s_pPathB2, this, menu_selector(MotionStreakTest::backCallback) );
- CCMenuItemImage *item2 = CCMenuItemImage::create(s_pPathR1, s_pPathR2, this, menu_selector(MotionStreakTest::restartCallback) );
- CCMenuItemImage *item3 = CCMenuItemImage::create(s_pPathF1, s_pPathF2, this, menu_selector(MotionStreakTest::nextCallback) );
- //创建菜单
- CCMenu *menu = CCMenu::create(item1, item2, item3, NULL);
- //设置菜单与各菜单项的位置
- menu->setPosition(CCPointZero);
- item1->setPosition(CCPointMake(s.width/2 - item2->getContentSize().width*2, item2->getContentSize().height/2));
- item2->setPosition(CCPointMake(s.width/2, item2->getContentSize().height/2));
- item3->setPosition(CCPointMake(s.width/2 + item2->getContentSize().width*2, item2->getContentSize().height/2));
- //将菜单加入当前层
- addChild(menu, 1);
- //创建一个菜单切换文字项,其实就是有复选框效果的文字标签。这里创建的切换项为“质量优先模式”和“效率优先模式”,响应函数为modeCallback。
- CCMenuItemToggle *itemMode = CCMenuItemToggle::createWithTarget(this, menu_selector(MotionStreakTest::modeCallback),
- CCMenuItemFont::create(“Use High Quality Mode”),
- CCMenuItemFont::create(“Use Fast Mode”),
- NULL);
- //创建第二个菜单并加入当前层
- CCMenu *menuMode = CCMenu::create(itemMode, NULL);
- addChild(menuMode);
- //设置菜单位置
- menuMode->setPosition(ccp(s.width/2, s.height/4));
- }
- //切换文字项的响应函数。
- void MotionStreakTest::modeCallback(CCObject *pSender)
- {
- //来回切换模式
- bool fastMode = streak->isFastMode();
- streak->setFastMode(! fastMode);
- }
- //重新演示当前效果。
- void MotionStreakTest::restartCallback(CCObject* pSender)
- {
- //创建一个演示场景。
- CCScene* s = new MotionStreakTestScene();//CCScene::create();
- s->addChild(restartMotionAction());
- //使用当前场景。
- CCDirector::sharedDirector()->replaceScene(s);
- s->release();
- }
- //下一个效果的演示
- void MotionStreakTest::nextCallback(CCObject* pSender)
- {
- //创建一个演示场景。
- CCScene* s = new MotionStreakTestScene();//CCScene::create();
- //将下一个演示层加入场景,并运行这个场景
- s->addChild( nextMotionAction() );
- CCDirector::sharedDirector()->replaceScene(s);
- s->release();
- }
- //上一个效果的演示
- void MotionStreakTest::backCallback(CCObject* pSender)
- { //创建一个演示场景。
- CCScene* s = new MotionStreakTestScene;//CCScene::create();
- //将上一个演示层加入场景,并运行这个场景
- s->addChild( backMotionAction() );
- CCDirector::sharedDirector()->replaceScene(s);
- s->release();
- }
然后是派生的第一个拖尾效果演示类:
[cpp] view plaincopy
- class MotionStreakTest1 : public MotionStreakTest
- {
- protected:
- //根结点
- CCNode* m_root;
- //带拖尾的目标结点
- CCNode* m_target;
- public:
- //加载当前层时的处理
- virtual void onEnter();
- //更新函数
- void onUpdate(float delta);
- //取得标题
- virtual std::string title();
- };
对应CPP:
[cpp] view plaincopy
- //加载当前层时的处理
- void MotionStreakTest1::onEnter()
- {
- //调用基类的相应函数。
- MotionStreakTest::onEnter();
- //取和屏幕大小
- CCSize s = CCDirector::sharedDirector()->getWinSize();
- // 创建根精灵结点,放入当前层中的屏幕中心位置。
- m_root = CCSprite::create(s_pPathR1);
- addChild(m_root, 1);
- m_root->setPosition(ccp(s.width/2, s.height/2));
- //创建目标精灵结点,放入根结点下的右边1/4屏幕宽度位置。
- m_target = CCSprite::create(s_pPathR1);
- m_root->addChild(m_target);
- m_target->setPosition(ccp(s.width/4, 0));
- // 创建拖尾效果并放入到当前层下。
- streak = CCMotionStreak::create(2, 3, 32, ccGREEN, s_streak);
- addChild(streak);
- //每帧调用onUpdate函数。
- schedule(schedule_selector(MotionStreakTest1::onUpdate));
- //创建一个旋转动画,2秒内自转360度。
- CCActionInterval* a1 = CCRotateBy::create(2, 360);
- //创建一个al1的无限循环动画。
- CCAction* action1 = CCRepeatForever::create(a1);
- //创建一个平移动画,2秒内向右移动100像素。
- CCActionInterval* motion = CCMoveBy::create(2, CCPointMake(100,0) );
- //根结点运行一个无限循环的动画序列,动画序列为平移动画及其反向动画。 m_root->runAction( CCRepeatForever::create((CCActionInterval*)(CCSequence::create(motion, motion->reverse(), NULL)) ) );
- //同时也运行无限循环的自转动画。
- m_root->runAction( action1 );
- //创建一个无限循环的动画序列,动画序列为7个变色动画,哪个结点使用它就会不断的变色。
- CCActionInterval *colorAction = CCRepeatForever::create((CCActionInterval *)CCSequence::create(
- CCTintTo::create(0.2f, 255, 0, 0),
- CCTintTo::create(0.2f, 0, 255, 0),
- CCTintTo::create(0.2f, 0, 0, 255),
- CCTintTo::create(0.2f, 0, 255, 255),
- CCTintTo::create(0.2f, 255, 255, 0),
- CCTintTo::create(0.2f, 255, 0, 255),
- CCTintTo::create(0.2f, 255, 255, 255),
- NULL));
- //让拖尾运行这个变色动画序列。
- streak->runAction(colorAction);
- }
- //实时更新函数。
- void MotionStreakTest1::onUpdate(float delta)
- {
- //更新拖尾的位置,设置为目标精灵结点的位置。
- streak->setPosition( m_target->convertToWorldSpace(CCPointZero) );
- }
- //取得标题。
- std::string MotionStreakTest1::title()
- {
- return “MotionStreak test 1”;
- }
演示如图:
派生的第二个拖尾效果演示类:
[cpp] view plaincopy
- class MotionStreakTest2 : public MotionStreakTest
- {
- //根结点
- CCNode* m_root;
- //带拖尾的目标结点
- CCNode* m_target;
- public:
- //加载当前层时的处理
- virtual void onEnter();
- //触屏并移动时响应处理
- void ccTouchesMoved(CCSet* touches, CCEvent* event);
- //取得标题
- virtual std::string title();
- };
对应的CPP:
[cpp] view plaincopy
- //加载当前层时的处理
- void MotionStreakTest2::onEnter()
- {
- //调用基类的相应函数。
- MotionStreakTest::onEnter();
- //这里设置打开触屏响应
- setTouchEnabled(true);
- //取得屏幕大小
- CCSize s = CCDirector::sharedDirector()->getWinSize();
- // 创建拖尾效果并放入到当前层下。
- streak = CCMotionStreak::create(3, 3, 64, ccWHITE, s_streak );
- addChild(streak);
- //设置拖尾的初始位置为屏幕中小。
- streak->setPosition( CCPointMake(s.width/2, s.height/2) );
- }
- //触屏并移动时响应处理
- void MotionStreakTest2::ccTouchesMoved(CCSet* touches, CCEvent* event)
- {
- //取得触点位置。
- CCSetIterator it = touches->begin();
- CCTouch* touch = (CCTouch*)(*it);
- CCPoint touchLocation = touch->getLocation();
- //设置为拖层的位置。
- streak->setPosition( touchLocation );
- }
- //取得标题
- std::string MotionStreakTest2::title()
- {
- return “MotionStreak test”;
- }
效果如图:
派生的第三个拖尾效果演示类:
[cpp] view plaincopy
- class Issue1358 : public MotionStreakTest
- {
- public:
- //取得标题
- virtual std::string title();
- //取得副标题
- virtual std::string subtitle();
- //加载当前层时的处理
- virtual void onEnter();
- //更新函数
- virtual void update(float dt);
- private:
- //中心位置
- CCPoint m_center;
- //半径
- float m_fRadius;
- //角度
- float m_fAngle;
- };
对应CPP:
[cpp] view plaincopy
- //加载当前层时的处理
- void Issue1358::onEnter()
- {
- //调用基类的相应函数。
- MotionStreakTest::onEnter();
- //取得屏幕位置
- CCSize size = CCDirector::sharedDirector()->getWinSize();
- // 创建拖尾效果并放入到当前层下。
- streak = CCMotionStreak::create(2.0f, 1.0f, 50.0f, ccc3(255, 255, 0), “Images/Icon.png”);
- addChild(streak);
- //初始化中心位置,半径和角度。
- m_center = ccp(size.width/2, size.height/2);
- m_fRadius = size.width/3;
- m_fAngle = 0.0f;
- //设置每帧的回调更新函数。
- schedule(schedule_selector(Issue1358::update), 0);
- }
- //每帧的回调更新函数。
- void Issue1358::update(float dt)
- {
- //角度增加1.0f
- m_fAngle += 1.0f;
- //计算拖尾的位置
- streak->setPosition(ccp(m_center.x + cosf(m_fAngle/180 * M_PI)*m_fRadius,
- m_center.y + sinf(m_fAngle/ 180 * M_PI)*m_fRadius));
- }
- //取得标题。
- std::string Issue1358::title()
- {
- return “Issue 1358”;
- }
- //取得副标题。
- std::string Issue1358::subtitle()
- {
- return “The tail should use the texture”;
- }
效果如图:
然后是演示用的场景:
[cpp] view plaincopy
- class MotionStreakTestScene : public TestScene
- {
- public:
- //运行场景的处理
- virtual void runThisTest();
- };
- //运行场景的处理
- void MotionStreakTestScene::runThisTest()
- {
- //创建下一个要演示的效果并放入当前场景中。
- CCLayer* pLayer = nextMotionAction();
- addChild(pLayer);
- //使用当前场景。
- CCDirector::sharedDirector()->replaceScene(this);
- }
总结一下:
拖尾效果的原理就是在相应距离内动态生成条带,然后逐渐消隐,在Cocos2d-x中可以指定这个最小距离,以及消隐的速度,还有条带的粗细,相应的纹理对象,都是通过CCMotionStreak 类来实现的。
又一篇结束了,看看时间,一点半了,为了今年的目标,我只能坚持下去。工作,写作,工具箱,一个都不能少!努力吧,骚年!