【深入了解cocos2d-x 3.x】一步一步通过ClippingNode实现一个功能完善的跑马灯公告(1)

这篇文章主要是通过一步一步实现一个功能完善的跑马灯公告来展示ClippingNode的用法并且最终深入ClippingNode的源码,了解其实现原理。

首先,先介绍一下ClippingNode,ClippingNode也叫裁剪节点,能将一些内容通过使用模板裁剪出来显示在界面上,可以实现一些很炫酷的效果。来看看今天要实现的效果

1、ClippingNode类分析

先来看看ClippingNode的声明文件 看看其中的public方法

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,现在先来做第一步。实现的代码如下:

	//设置模板
	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将跑马灯动起来,跑马灯一般需要先将文字左移,移动到文字看不见的时候再将文字移除或者隐藏,代码如下(为了简便,就直接设置隐藏了):

	auto sequ = Sequence::create(MoveBy::create(5.0f, Vec2(-text->getContentSize().width, 0)), Hide::create(), nullptr);
	text->runAction(sequ);

现在跑马灯的样子就如同开篇展示的那样了,可是这样还不能直接使用,因为这只是一串代码,还需要对其进行一定的封装,然后提供一个非常简便的方法给别的类调用。

3、封装

现在我们从便捷性的角度考虑如何将跑马灯功能封装成一个函数供其他类调用。首先提取出函数的参数,分别是:显示区域,跑马灯文字,字体字号,跑马灯位置,跑马灯的父节点。下面是初步封装好的一套跑马灯函数的声明:

void showMarquee(Node* parent, const std::string& text, const std::string& font, float fontSize, const Rect& showRect, const Vec2& position);

看参数是不是有些略多,每次调用这个函数是不是非常的不方便,那么我们现在来看看究竟有那些参数是必须要传入的吧。每次调用跑马灯显示的文字都会改变,其他的参数在一个游戏中是不会改变的。那么就有必要做一个类来保证使用方法的便捷性了。

首先,我们简单的构建一下一个跑马灯类,如下

#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方法的实现

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);
}

这样就可以通过以下的调用方法来调用跑马灯了

<span style="white-space:pre">	</span>Marquee* m = Marquee::create();
	m->show("----hhahahah veeeeee-----");
	m->setPosition(Vec2(700, 300));
	this->addChild(m);

4、完善

未完待续

时间: 2024-08-26 15:35:42

【深入了解cocos2d-x 3.x】一步一步通过ClippingNode实现一个功能完善的跑马灯公告(1)的相关文章

一步一步学习Vue(十一)

本篇继续学习vuex,还是以实例为主:我们以一步一步学Vue(四)中讲述的例子为基础,对其改造,基于vuex重构一遍,这是原始的代码: todolist.js ; (function () { var list = []; var Todo = (function () { var id = 1; return function (title, desc) { this.title = title; this.desc = desc; this.id = id++; } })(); /** *

.NET跨平台:在Mac上跟着错误信息一步一步手写ASP.NET 5程序

今天坐高铁时尝试了一种学习ASP.NET 5的笨方法,从空文件夹开始,根据运行dnx . kestrel命令的错误信息,一步一步写代码,直至将一个最简单的ASP.NET程序运行起来. 尝试的具体步骤如下. 新建一个空文件夹HelloCnblogs: mkdir HelloCnblogs && cd $_ 在这个空HelloCnblogs文件夹中运行 dnx . kestrel 命令(基于CoreCLR的dnx),运行结果是如下的出错信息: System.InvalidOperationEx

一步一步跟我学习lucene(19)---lucene增量更新和NRT(near-real-time)Query近实时查询

这两天加班,不能兼顾博客的更新,请大家见谅. 有时候我们创建完索引之后,数据源可能有更新的内容,而我们又想像数据库那样能直接体现在查询中,这里就是我们所说的增量索引.对于这样的需求我们怎么来实现呢?lucene内部是没有提供这种增量索引的实现的: 这里我们一般可能会想到,将之前的索引全部删除,然后进行索引的重建.对于这种做法,如果数据源的条数不是特别大的情况下倒还可以,如果数据源的条数特别大的话,势必会造成查询数据耗时,同时索引的构建也是比较耗时的,几相叠加,势必可能造成查询的时候数据缺失的情况

一步一步跟我学习lucene(9)---lucene搜索之拼写检查和相似度查询提示(spellcheck)

suggest应用场景 用户的输入行为是不确定的,而我们在写程序的时候总是想让用户按照指定的内容或指定格式的内容进行搜索,这里就要进行人工干预用户输入的搜索条件了:我们在用百度谷歌等搜索引擎的时候经常会看到按键放下的时候直接会提示用户是否想搜索某些相关的内容,恰好lucene在开发的时候想到了这一点,lucene提供的suggest包正是用来解决上述问题的. suggest包联想词相关介绍 suggest包提供了lucene的自动补全或者拼写检查的支持: 拼写检查相关的类在org.apache.

loadrunner安装运行一步一步来(多图)

安装loadrunner 一路遇到很多坑,很多坑,坑,为什么呢? 因为这软件是收费的,他操作文档写的很详细,就是不写基础环境的配置,下面安装过程写详细一些,减少大家没必要时间上的浪费和对此的谩骂 现在loadrunner 12的版本已经出来了,不过还没有破解,所以先安装测试11的版本,不绕圈子,先下载, 链接: http://pan.baidu.com/s/1kT8CbVh 密码: v4br 加密码是怕被删 遇到的坑 下面是通用的安装说明: 1.下载loadrunner-11.zip文件,解压缩

Rhythmk 一步一步学 JAVA (21) JAVA 多线程

1.JAVA多线程简单示例 1.1 .Thread  集成接口 Runnable 1.2 .线程状态,可以通过  Thread.getState()获取线程状态: New (新创建) Runnable (可以运行) Blocked  (被阻塞) Waiting  (等待) Timed waiting (计时等待) Terminated  (被终止) ? 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

Rhythmk 一步一步学 JAVA (20) JAVA enum常用方法

JAVA 枚举定义常用方法: 1.static Enum valueOf(Class enum,String name) 返回指定name的枚举类型 2.Static Enum values[] 返回枚举常量集合 ? 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

一步一步学习IdentityServer3 (1)

学习之初: IdentityServer3我自己最开始了解到的就是做一个SSO单点登录,后面发现还有单独的认证服务功能,其实它还可以做APIs的访问控制,资源授权,另外还可以为提供第三方登录,其他的自由定制目前也在学习中. 网络飞速发展的今天,庞大的数据,庞大的用户,庞大的业务,都需要登录的支撑,登录授权完全看作一个单独的一门技术,Web端需要登录,App端需要登录,Api需要授权访问等等,除此以外大型业务系统,子系统之间其实也需要这样一个登陆授权,所以,登录不再是单一的一个功能点了,简单的查询

C#进阶系列——一步一步封装自己的HtmlHelper组件:BootstrapHelper(二)

前言:上篇介绍了下封装BootstrapHelper的一些基础知识,这篇继续来完善下.参考HtmlHelper的方式,这篇博主先来封装下一些常用的表单组件.关于BootstrapHelper封装的意义何在,上篇评论里面已经讨论得太多,这里也不想过多纠结.总之一句话:凡事有得必有失,就看你怎么去取舍.有兴趣的可以看看,没兴趣的权当博主讲了个“笑话”吧. 本文原创地址:http://www.cnblogs.com/landeanfen/p/5746166.html BootstrapHelper系列