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)相关推荐

  1. nunito字体_dcat-admin: 使用很少的代码快速构建一个功能完善的高颜值后台系统,内置丰富的后台常用组件,开箱即用,让开发者告别冗杂的HTML代码。...

    Dcat Admin是一个基于laravel-admin二次开发而成的后台系统构建工具,只需很少的代码即可快速构建出一个功能完善的高颜值后台系统.内置丰富的后台常用组件,开箱即用,让开发者告别冗杂的H ...

  2. html跑马灯编程,求一个HTML无缝的跑马灯代码。

    属性要求:胆识.福缘.机敏 效果:中毒.抗毒 蛤蟆功: 首部曲 1.巳午未时点扬州武器商附近的全知道触发到对话..说有事情想请教,一阵对话后给他10万两.接着说要到华山去(若给他1000两的是昆仑剑法 ...

  3. 第一个ARM实验(跑马灯)

    要成功完成基于ARM板的跑马灯实验首先需要:硬件(ARM板),软件(ADS1_2,JLINK,GIVEIO) 现在我们准备好了软件,先对软件进行安装! 一.对ADS1_2的安装: 1.点击进行安装, ...

  4. Unity EasyToutch5X 实现一个简单的手指跑马灯游戏

    前几天突然翻到14年高中上体育课时的一张合照,人数不多,却占据了我几乎占据了我高中的三年时光.满满的思绪乱飞.因为高中毕业之后就没再联系过,一直静静地躺在列表中,所以就联系了高中时期的一部分同学准备聚 ...

  5. php模拟超级课程表,一个功能完善、UI简洁的仿超级课程表的课表控件 TimetableView...

    TimetableView 一个非常漂亮的Android课程表控件,该控件支持的功能: 设置数据源 颜色设置,控件内置17种颜色 触感反馈,每种内置颜色都有对应的三个样式 日期显示与高亮 课表Item ...

  6. android 除了webview 浏览器控件,AgentWeb是基于Android WebView一个功能完善小型浏览器库...

    [技巧沙龙]AI开辟者拭魅战营-7分钟打造1个定制技能.7月22号,我们等你一路! Android 端 AgentWeb 介绍 AgentWeb是一个高度封装的 Android WebView ,简单 ...

  7. 如何编写一个功能完善的HTTP服务器

        YC服务器是可扩展的HTTP服务器,它的源码文件是ychttp.cpp.     使用YSP语言生成的网页或数据可以通过YC服务器传给浏览器及各种客户终端.下面是该服务器的源码. -- typ ...

  8. 写一个ST语言的跑马灯程序

    ST语言的跑马灯程序如下: repeat for i:=1 to 8 do for j:=1 to 8 do if (i=j) then write('*'); else write(' '); en ...

  9. 这是一个有关于点击按钮选图片然后有跑马灯的界面????

    任务要求实现一个图片选择器和一个很6的跑马灯 嗯,反正看到就一脸懵B了 图片选择器怪麻烦的,就先跑马灯(滚动字幕)吧=- = 效果图如下: 无奈机子很卡= = 嗯截图很费劲 那么就来讲一下怎么弄的吧= ...

最新文章

  1. python实现文件搜索_python实现搜索指定目录下文件及文件内搜索指定关键词的方法...
  2. GridView 用 checkbox 全选并取值
  3. Algorithm之RS:RS常用的一些库
  4. .net core 2.0部署到CentOS7系统
  5. 高等数学超入门学习笔记
  6. rtsp摘要认证协议(Response计算方法)
  7. .某学校的学生公寓有14栋楼,用A~N这14个大写字母的其中一个代表楼号,每栋楼的层数为6层,用1~6六个数字表示。每层楼有40个房间,编号为01~40。具体表示一个宿舍房间时,用1个字母加3位数字表
  8. python 24位图转 8位_Python爬取PPT模板小工具下载-Python爬取PPT模板小工具免费版下载v1.0...
  9. WEB流程设计器 = jQuery + jsPlumb + Bootstrap
  10. 华为主导 5G 入网之争?
  11. C++ STL中vector的内存机制和性能分析
  12. oracle开发的小技巧(原创)
  13. 分子动力学模拟-gromacs的基本使用
  14. n卡驱动要下java吗_N卡驱动要下载哪一个?NVIDIA显卡驱动下载方法
  15. Radon变换与Matlab代码
  16. Android 自定义View漫飞舞超炫超浪漫特效
  17. 过滤器Filter的介绍
  18. 蚌埠市哪有学计算机编程的,蚌埠小孩学习编程
  19. [HAOI2012]外星人——数论欧拉函数
  20. 安卓开发— —仿微信界面(二)

热门文章

  1. linux孟庆昌第六章课后题_第六章课后练习题答案
  2. 2014_anshan_onsite
  3. 排序(基本概念及分类,直接插入排序和希尔排序)
  4. 【报错解决】linux网络编程报错storage size of ‘serv_addr’ isn’t known解决办法
  5. 数据库以及表的基本操作
  6. JavaScript知识笔记(一)——入门、语句、注释、变量、函数、输出内容、对话框、窗口
  7. 关于同时可用git命令clone和TortoiseGit拉取代码不需要密码
  8. 移动pc常用Meta标签
  9. react事件处理函数中绑定this的bind()函数
  10. Java-Character String StringBuffer StringBuilder