本文部分代码来自http://blog.csdn.net/q229827701/article/details/39996171,在此基础上稍作修改,并添加了详细注释。
1、ScrollText类
//.h #ifndef __ScrollTest__ScrollTest__ #define __ScrollTest__ScrollTest__ #include "cocos2d.h" USING_NS_CC; class ScrollText : public cocos2d::Node { public: CREATE_FUNC(ScrollText); static ScrollText* create(Sprite* &pMask,Node* &pMoveChild,Node* &otherChild,...); void setAutoScroll(bool isScroll,bool byWidth = false); Node* _mLabel; CC_CONSTRUCTOR_ACCESS: ScrollText(); virtual ~ScrollText(); virtual bool init(); virtual bool initWithDatas(Sprite* &pMask,Node* &pMoveChild); bool initClipper(Sprite* &pMask,Node* &pMoveChild); void update(float delta); private: Vector<Node*> _mNodes; bool _autoScroll; }; #endif /* defined(__ScrollTest__ScrollTest__) */
//.cpp #include "ScrollTest.h" #include <stdarg.h> USING_NS_CC; #define IF_RETURN(cont,p) if((cont)){return (p);} #define IF_RETURN_FALSE(cont) IF_RETURN(cont,false) //创建ScrollText使用create()时,调用该函数,默认的创建对象方法 bool ScrollText::init() { bool bRet = false; do{ CC_BREAK_IF(!Node::init()); auto pMask = Sprite::create("blue_btn.png");//设置遮罩模板 _mLabel = Label::createWithSystemFont("Title","Arial-BoldMT",30);//设置需要循环播放的内容 _mLabel->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);//设置锚点 IF_RETURN_FALSE(!initClipper(pMask,_mLabel));//初始化剪裁节点,并判断是否成功 scheduleUpdate();//帧更新,每帧更新一次 setAutoScroll(true);//设置可以自动循环播放 bRet = true; }while(0); return bRet; } //初始化剪裁节点,参数1:遮罩模板,即跑马灯可以看到的区域,参数2:跑马灯内容,即上面创建的_mLabel。参数传递的是指针的引用 //个人建议initCliper可以不用传参,把参数设置成成员函数就好了,并且这些成员函数设为public,这样可以随时更改遮罩模板和跑马灯内容 bool ScrollText::initClipper(cocos2d::Sprite *&pMask,cocos2d::Node *&pMoveChild) { //创建剪裁节点 auto clipper = ClippingNode::create(); //判断剪裁节点和剪裁模板是否为非NULL IF_RETURN_FALSE(!clipper); IF_RETURN_FALSE(!pMask); //设置节点Node的尺寸为剪裁模板的尺寸,即上面Sprite对象的尺寸。Node的特性是本身不会显示任何内容,但是可以把任何内容放到Node中 setContentSize(pMask->getContentSize()); //获取遮罩模板的切图 IF_RETURN_FALSE(!pMask->getTexture()); auto _clipperStencil = Sprite::createWithTexture(pMask->getTexture()); IF_RETURN_FALSE(!_clipperStencil); //剪裁节点属性设置,设置0.1使得模板区域可见,模板外不可见 clipper->setAlphaThreshold(0.1f); //设置剪裁模板 clipper->setStencil(_clipperStencil); //将跑马灯的对象加入到剪裁节点中 clipper->addChild(pMoveChild,1); //剪裁节点加入Node addChild(clipper); //以下是使用可变参数create创建的对象,遍历对象容器,依次加入剪裁节点。此处该设置下子节点的位置 for(auto child:_mNodes) { IF_RETURN_FALSE(!child); clipper->addChild(child); } return true; } //默认构造函数,在new时调用 ScrollText::ScrollText() :_autoScroll(false) { } //析构函数,安全释放m_Label ScrollText::~ScrollText() { CC_SAFE_RELEASE(_mLabel); } //帧更新调用的函数 void ScrollText::update(float delta) { //跑马灯内容节点创建失败,直接返回 if(!_mLabel) { return; } //获取用于设置字体循环播放的数据 float contentX = getContentSize().width*(-1.0f); float labelX = _mLabel->getContentSize().width*(-1.0f); if(_autoScroll) { //跑马灯设置为true,且跑马灯当前位置大于labelX和contentX/2之和(这是一个负数),即跑马灯的内容节点,还未完全跑出遮罩模板的范围,每帧X轴方向-1 //此处也可以用动作。 if(_mLabel->getPositionX() >= (labelX+contentX/2)) _mLabel->setPositionX(_mLabel->getPositionX() - 1.0f); else _mLabel->setPositionX(-contentX / 2);//如果跑出遮罩范围,则将跑马灯内容节点放回初始位置 }else { _mLabel->setPositionX(contentX/2); } } void ScrollText::setAutoScroll(bool isScroll,bool byWidth/*false*/) { //设置是否循环,如果通过跑马灯内容的宽度来设置_autoScroll为false,即此时内容的宽度不超过遮罩模板的宽度 if(!byWidth) { _autoScroll = isScroll; }else{ //如果内容超出了遮罩模板的宽度,则循环播放,如果没有超出,则不循环播放 _autoScroll = _mLabel->getContentSize().width > getContentSize().width ? true : false; } } //可变参数创建跑马灯 ScrollText* ScrollText::create(cocos2d::Sprite *&pMask,cocos2d::Node *&pMoveChild,cocos2d::Node *&otherChild,...) { auto sTxt = new ScrollText(); //遍历参数,指针引用 if(sTxt) { va_list lst; va_start(lst,otherChild); Node* pNow; pNow = otherChild; while(otherChild) { if(pNow) { sTxt->_mNodes.pushBack(pNow);//加入node容器 pNow = va_arg(lst,Node*); }else break; } va_end(lst); if(sTxt->initWithDatas(pMask,pMoveChild))//初始化剪裁节点,并在初始化剪裁节点中初始化跑马灯内容节点 { sTxt->autorelease(); return sTxt; }else//创建失败的安全释放,防止野指针的出现 { delete sTxt; sTxt = NULL; return NULL; } }else{ delete sTxt; sTxt = NULL; return NULL; } } //初始化 bool ScrollText::initWithDatas(cocos2d::Sprite *&pMask,cocos2d::Node *&pMoveChild) { bool bRet = false; do{ CC_BREAK_IF(!Node::init()); IF_RETURN_FALSE(!pMask); _mLabel = pMoveChild; _mLabel->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT); initClipper(pMask,_mLabel);//初始化剪裁节点,并初始化跑马灯的内容 scheduleUpdate(); bRet = true; }while(0); return bRet; }
2、类的使用
auto st = ScrollText::create(); (static_cast<Label*>(st->_mLabel))->setString("这是我的第一个跑马灯,Perfect!"); st->setPosition(visibleSize.width/2,visibleSize.height/2); addChild(st);