Cocos2d-x 3.2:通过ClippingNode实现一个功能完善的跑马灯公告(1)
Cocos2d-x 3.2:通過ClippingNode實現一個功能完善的跑馬燈公告(1)
本文轉載至深入理解Cocos2d-x 3.x:一步一步通過ClippingNode實現一個功能完善的跑馬燈公告(1)
?
這篇文章主要是通過一步一步實現一個功能完善的跑馬燈公告來展示ClippingNode的用法并且最終深入ClippingNode的源碼,了解其實現原理。
首先,先介紹一下ClippingNode,ClippingNode也叫裁剪節點,能將一些內容通過使用模板裁剪出來顯示在界面上,可以實現一些很炫酷的效果。來看看今天要實現的效果
1、ClippingNode類分析
先來看看ClippingNode的聲明文件 看看其中的public方法
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class?CC_DLL?ClippingNode?:?public?Node?? {?? public:?? ????static?ClippingNode*?create();?? ????static?ClippingNode*?create(Node?*stencil);?? ??? ????Node*?getStencil()?const;?? ????void?setStencil(Node?*stencil);?? ??? ????virtual?bool?hasContent()?const;?? ??? ????GLfloat?getAlphaThreshold()?const;?? ????void?setAlphaThreshold(GLfloat?alphaThreshold);?? ??????? ????bool?isInverted()?const;?? ????void?setInverted(bool?inverted);?? }; |
首先是create,這個方法是用于創建一個ClippingNode,這個就不多做贅述了,第二個create是創建一個帶遮罩模板的裁剪節點。
接下來的getStencil和setStencil分別是獲取和設置一個遮罩模板,裁剪物體方法就是通過這個遮罩模板的,遮罩模板只要是基于Node的對象都可以(非常重要)。
接下來的hasContent返回其是否有需要繪制的內容,如果沒有繪制的內容則返回false,有則返回true。
getAlphaThreshold 和setAlphaThreshold分別是獲取和設置一個像素的透明度值,取值范圍從0-1,其中0表示都不繪制,1表示都繪制。0.5表示透明度在 0.5以上的都繪制,這個函數涉及到opengl的Alpha測試的相關概念,Alpha測試的作用通過一句話解釋就是:所有像素的透明度值低于某個閥值 的統統拋棄,不繪制到屏幕上。
最后的isInverted和setInverted分別表示繪制的內容是模板內的還是模板外的,其效果如下:
2、簡易跑馬燈實現
上節簡單介紹了一下ClippingNode的函數,這節就通過實現一個簡易的跑馬燈功能來直觀的了解。首先介紹一下制作跑馬燈的思路。
首先我們需要將跑馬燈中的一部分超出的字裁剪掉,不讓他顯示在界面上。這就需要用到ClippingNode,現在先來做第一步。實現的代碼如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //設置模板?? auto?stencil?=?Sprite::create();?? //設置顯示區域大小?? stencil->setTextureRect(Rect(0,?0,?50,?30));?? ??? //設置跑馬燈文字?? auto?text?=?Label::createWithSystemFont("-1dasdasdasd?efadaewfevgds?dfhrthrbgrg1-",?"",?24);?? //設置錨點?? text->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT);?? ??? //創建裁剪節點?? auto?clippingNode?=?ClippingNode::create(stencil);?? //設置節點位置?? clippingNode->setPosition(Vec2(700,?400));?? //顯示模板內的內容?? clippingNode->setInverted(false);?? //添加顯示內容?? clippingNode->addChild(text,?2);?? //加入到UI樹?? addChild(clippingNode); |
上述的每一句代碼都有注釋,就不再多解釋了,這一步實現出來的效果如下圖,但是跑馬燈還不能動起來,待會我們就將跑馬燈動起來。
現在我們就設計一個Action將跑馬燈動起來,跑馬燈一般需要先將文字左移,移動到文字看不見的時候再將文字移除或者隱藏,代碼如下(為了簡便,就直接設置隱藏了):
| 1 2 | auto?sequ?=?Sequence::create(MoveBy::create(5.0f,?Vec2(-text->getContentSize().width,?0)),?Hide::create(),?nullptr);?? text->runAction(sequ); |
現在跑馬燈的樣子就如同開篇展示的那樣了,可是這樣還不能直接使用,因為這只是一串代碼,還需要對其進行一定的封裝,然后提供一個非常簡便的方法給別的類調用。
3、封裝
現在我們從便捷性的角度考慮如何將跑馬燈功能封裝成一個函數供其他類調用。首先提取出函數的參數,分別是:顯示區域,跑馬燈文字,字體字號,跑馬燈位置,跑馬燈的父節點。下面是初步封裝好的一套跑馬燈函數的聲明:
| 1 | void?showMarquee(Node*?parent,?const?std::string&?text,?const?std::string&?font,?float?fontSize,?const?Rect&?showRect,?const?Vec2&?position); |
看參數是不是有些略多,每次調用這個函數是不是非常的不方便,那么我們現在來看看究竟有那些參數是必須要傳入的吧。每次調用跑馬燈顯示的文字都會改變,其他的參數在一個游戲中是不會改變的。那么就有必要做一個類來保證使用方法的便捷性了。
首先,我們簡單的構建一下一個跑馬燈類,如下
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #include?"cocos2d.h"?? ??? USING_NS_CC;?? ??? class?Marquee?:?public?Node?? {?? public:?? ??? ????CREATE_FUNC(Marquee);?? ??? ????bool?init();?? ??? ????void?show(const?std::string&?text);?? ??? public:?? ????const?std::string&?getFont()?const?{?return?_font;?}?? ????void?setFont(std::string&?font)?{?_font?=?font;?}?? ????float?getFontSize()?const?{?return?_fontSize;?}?? ????void?setFontSize(float?fontSize)?{?_fontSize?=?fontSize;?}?? ??? public:?? ????const?Rect&?getShowRect()?const?{?return?_showRect;?}?? ????void?setShowRect(Rect&?showRect)?{?_showRect?=?showRect;?}?? protected:?? ????Marquee()?:??? ????????_font(""),?? ????????_fontSize(24),?? ????????_showRect(Rect(0,0,200,30))?? ????{};?? ????~Marquee()?{};?? ??? private:?? ????std::string?_font;?? ????float?_fontSize;?? ??? ????Rect?_showRect;?? }; |
然后是最重要的init方法和show方法的實現
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | bool?Marquee::init()?? {?? ????//設置模板?? ????auto?stencil?=?Sprite::create();?? ????//設置顯示區域大小?? ????stencil->setTextureRect(_showRect);?? ??? ????//設置跑馬燈文字?? ????_label?=?Label::createWithSystemFont("",?_font,?_fontSize);?? ????//設置錨點?? ????_label->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT);?? ??? ????_label->setAlignment(TextHAlignment::LEFT);?? ??? ????//創建裁剪節點?? ????auto?clippingNode?=?ClippingNode::create(stencil);?? ????//顯示模板內的內容?? ????clippingNode->setInverted(false);?? ????//添加顯示內容?? ????clippingNode->addChild(_label);?? ????//加入到UI樹?? ????addChild(clippingNode);?? ??? ????return?true;?? }?? ??? void?Marquee::show(const?std::string&?text)?? {?? ????_label->setString(text);?? ????_label->setPosition(Vec2(0,?_label->getContentSize().height?/?2));?? ??? ????auto?sequ?=?Sequence::create(MoveBy::create(5.0f,?Vec2(-_label->getContentSize().width,?0)),?Hide::create(),?nullptr);?? ????_label->runAction(sequ);?? } |
這樣就可以通過以下的調用方法來調用跑馬燈了
| 1 2 3 4 | Marquee*?m?=?Marquee::create();?? ????m->show("----hhahahah?veeeeee-----");?? ????m->setPosition(Vec2(700,?300));?? ????this->addChild(m); |
4、完善
看 上去,此前的步驟我們已經完成了一個跑馬燈的功能,實際上這個類距離真正能使用還差那么一點點,因為傳入跑馬燈的消息的傳入時機是不確定的,可能這一條消 息還沒有播放完成下一條就要開始播放了。這樣就需要實現一個播放等待隊列,將需要播放的消息加入播放隊列,然后跑馬燈自動判斷是否需要顯示。下面是改進后 的類聲明文件以及實現文件。
.h:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #include?"cocos2d.h"?? ??? USING_NS_CC;?? ??? class?Marquee?:?public?Node?? {?? public:?? ????enum?class?State?? ????{?? ????????idle,?? ????????playing,?? ????};?? ??? public:?? ??? ????CREATE_FUNC(Marquee);?? ??? ????bool?init();?? ??? ????void?addMessage(const?std::string&?text);?? ??? public:?? ????const?std::string&?getFont()?const?{?return?_font;?}?? ????void?setFont(std::string&?font)?{?_font?=?font;?}?? ????float?getFontSize()?const?{?return?_fontSize;?}?? ????void?setFontSize(float?fontSize)?{?_fontSize?=?fontSize;?}?? ??? public:?? ????const?Rect&?getShowRect()?const?{?return?_showRect;?}?? ????void?setShowRect(Rect&?showRect)?{?_showRect?=?showRect;?}?? ??? public:?? ????const?State&?getState()?const?{?return?_state;?}?? ??? protected:?? ????Marquee()?:??? ????????_font(""),?? ????????_fontSize(24),?? ????????_showRect(Rect(0,0,200,30)),?? ????????_state(State::idle)?? ????{};?? ????~Marquee()?{};?? ????void?show(const?std::string&?text);?? ??? private:?? ????State?_state;?? ??? private:?? ????std::string?_font;?? ????float?_fontSize;?? ??? ????Rect?_showRect;?? ??? private:?? ????Label?*?_label;?? ??? private:?? ????std::queue<std::string>?_texts;?? }; |
.cpp:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | #include?<Marquee.h>?? ??? bool?Marquee::init()?? {?? ????//設置模板?? ????auto?stencil?=?Sprite::create();?? ????//設置顯示區域大小?? ????stencil->setTextureRect(_showRect);?? ??? ????//設置跑馬燈文字?? ????_label?=?Label::createWithSystemFont("",?_font,?_fontSize);?? ????//設置錨點?? ????_label->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT);?? ??? ????_label->setAlignment(TextHAlignment::LEFT);?? ??? ????//創建裁剪節點?? ????auto?clippingNode?=?ClippingNode::create(stencil);?? ????//顯示模板內的內容?? ????clippingNode->setInverted(false);?? ????//添加顯示內容?? ????clippingNode->addChild(_label);?? ????//加入到UI樹?? ????addChild(clippingNode);?? ????stencil->setColor(Color3B::BLACK);?? ????addChild(stencil,?-1);?? ??? ????return?true;?? }?? ??? void?Marquee::show(const?std::string&?text)?? {?? ????_state?=?State::playing;?? ??? ????_label->setString(text);?? ????_label->setPosition(Vec2(0,?0));?? ??? ????auto?sequ?=?Sequence::create(?? ????????Show::create(),??? ????????MoveBy::create(5.0f,?Vec2(-(_label->getContentSize().width?+?_showRect.size.width?/?2),?0)),?? ????????Hide::create()?,?DelayTime::create(1.0f),??? ????????CCCallFunc::create([&]()?? ????{?? ????????if?(_texts.size()?==?0)?? ????????{?? ????????????_state?=?State::idle;?? ????????}?? ????????else?? ????????{?? ????????????show(_texts.front());?? ????????????_texts.pop();?? ????????}?? ????}),?nullptr);?? ????_label->runAction(sequ);?? }?? ??? void?Marquee::addMessage(const?std::string&?text)?? {?? ????if?(text.empty())?? ????{?? ????????return;?? ????}?? ??????? ????if?(_state?==?State::idle)?? ????{?? ????????show(text);?? ????}?? ????else?? ????{?? ????????_texts.push(text);?? ????}?? } |
此處將show方法隱藏,并且提供了addMessage方法,內部實現了一個有限狀態機,根據狀態來顯示剩余的消息,其使用方法與此前相似:
| 1 2 3 4 | m?=?Marquee::create();?? m->addMessage("----hhahahah?veeeeee-----");?? m->setPosition(Vec2(700,?300));?? this->addChild(m); |
?
轉載于:https://www.cnblogs.com/dudu580231/p/4560310.html
總結
以上是生活随笔為你收集整理的Cocos2d-x 3.2:通过ClippingNode实现一个功能完善的跑马灯公告(1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到鱼在热水里是什么意思
- 下一篇: 朋友梦到我瘦了是什么意思