cocos2dx[3.2](19)——裁剪节点ClippingNode

【唠叨】

学习cocos2dx 3.2确实比较吃力,因为网上关于最新版的v3.2的资料十分稀少,或者是讲解的确实不是很详细。大部分人都是根据官方文档照样画瓢,而对于有些比较抽象的概念及函数都是照着官方文档来讲解的。这样的结果,导致有些东西令我确实非常费解。

没有办法,只好自己来总结cocos2dx3.2,然后将个人的学习感悟分享给大家。

PS:当然有些大牛写的文章还是很不错的。

有时候我们需要显示一张图片的部分区域,比如文字遮罩图片遮罩。。。

本节要讲的ClippingNode的功能效果大致就是上面所看到的遮罩效果。

【致谢】

http://cn.cocos2d-x.org/article/index?type=cocos2d-x&url=/doc/cocos-docs-master/manual/framework/native/v3/ClippingNode/zh.md

http://www.waitingfy.com/archives/1093 (“文字遮罩效果”)

【Demo下载】

http://down.51cto.com/data/1881321



【ClippingNode】

1、原理

ClippingNode(裁剪节点)可以用来对节点进行裁剪。ClippingNode是Node的子类,可以像普通节点一样放入Layer,Scene,Node中。

主要是根据一个模板(Stencil)切割图片的节点,生成任何形状的节点显示。

ClippingNode是利用模板遮罩来完成对Node区域裁剪的技术。

如何理解ClippingNode的遮罩?看下图的例子吧。

2、举例说明

> 模板(Stencil):可以使用Layer、Node、Sprite等。

> 底板           :可以使用Layer、Node、Sprite等。

> Layer层

2.1、第一组(Layer层无背景图片)

> 模板(Stencil):模板为Node节点,放入5个Sprite的小球

> 底板           :底板为Node节点,放入1个Sprite的ABCD图

> Layer层        :无元素,背景颜色为黑色

            

> 裁剪遮罩效果示意图:

2.2、第二组(Layer层有背景图片)

> 模板(Stencil):模板为Node节点,放入5个Sprite的小球

> 底板           :底板为Node节点,放入1个Sprite的ABCD图

> Layer层        :有一个Sprite的cocos2dx背景图片

            

> 裁剪遮罩效果示意图:

  2.3、分析总结

通过ClippingNode进行裁剪遮罩,其实是这样的:

> 将模板(Stencil)上所有元素的形状集合作为“形状模板”,其元素本身不渲染。

> 使用“形状模板”对底板进行裁剪。

> 显示从底板上裁剪下来的图片区域。

总的来说:

        > 模板(Stencil)相当于是一个样板,上面有很多不同形状的"洞洞"。

        > 然后根据样板,对底板进行裁剪,"挖洞"。

        > 然后将剪下来的那些碎片,按照原来的位置进行摆放。

其中:模板(Stencil)只是一个“形状模板”,本身的图片是不进行绘制的。

3、主要函数

ClippingNode继承于Node类,用于节点的裁剪与遮罩。

3.1、创建ClippingNode

两种方式:是否使用模板(stencil)来创建。

//
	//创建,不含模板(stencil)
	ClippingNode* clippingNode = ClippingNode::create();

	//创建,使用模板(stencil)
	ClippingNode* clippingNode = ClippingNode::create(stencil);
//

3.2、设置模板(Stencil)

模板节点是Node的子类,一般常常使用DrawNode,因为它可以绘制不同形状的图形。当然也可以直接使用Node节点作为作为模板。

//
/**
 *		用来做裁剪的模板(stencil)节点(Node)
 *		模板(stencil)对象,默认为空(nullptr)
 **/
	Node* stencil = Node::create();    //模板stencil节点Node

	stencil->addChild(spriteBall1);    //添加小球1
	stencil->addChild(spriteBall2);    //添加小球2
	stencil->addChild(spriteBall3);    //添加小球3
	stencil->addChild(spriteBall4);    //添加小球4
	stencil->addChild(spriteBall5);    //添加小球5

	clippingNode->setStencil(stencil); //设置模板Stencil
//

3.3、设置底板(Content)

//
	//创建ClippingNode后,使用addChild()添加的节点,即为底板内容
	clippingNode->addChild(content); //设置底板
//

3.4、倒置显示(Inverted)

    > false :显示被模板裁剪下来的底板内容。默认为false。

    > true  :显示剩余部分。

//
	//默认为false
	//表示显示被裁剪下来的底板内容
	clippingNode->setInverted(false);
//

3.5、alpha阈值(alphaThreshold)

> alpha:表示像素的透明度值。

> 只有模板(stencil)中像素的alpha值大于alpha阈值时,内容才会被绘制。

> alpha阈值(alphaThreshold):取值范围[0,1]

默认为 1 ,表示alpha测试默认关闭,即全部绘制。

> 若不是1  ,表示只绘制模板中,alpha像素大于alphaThreshold的内容。

//
	//设置alpha透明度闸值
	//即显示模板中,alpha像素大于0.05的内容
	holesClipper->setAlphaThreshold(0.05f); 
//

具体说明:

以下是一张40*40的图片,其中小球以外的其他区域像素为透明的(即:alpha为 0 )。

(1)在不设置AlphaThreshold闸值或者setAlphaThreshold(1.0f),的情况下:

(2)在设置setAlphaThreshold(0.5f),的情况下:

(3)结论:

> 可以发现在不设置alpha闸值时,模板绘制的区域为一个40*40的矩形。

> 设置了alpha闸值为0.5时,透明度alpha为0的像素不被绘制,只绘制了一个小圆。



【代码实战】

这里讲几个有意思的例子。

> 官方的“打洞”

> “文字遮罩闪亮特效”

> ClippingNode类的用途很广泛,更多用法自行百度。

1、官方的“打洞”

官方cpp-test项目里有一个使用ClippingNode完成“打洞”效果的例子,我觉得挺有意思的。

更多的用法参见官方的cpp-test项目。

先来看看效果:

  1.1、素材

        

        

  1.2、在HelloWorld.h中添加如下变量与函数

//
	ClippingNode* holesClipper; //裁剪节点
	Node* holesStencil;         //模板节点
	Node* holes;                //底板节点
	 
	//触摸回调
	void onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event);
	//添加小洞
	void pokeHoleAtPoint(Vec2 point);
//

  1.3、在HelloWorld.cpp中的init()中创建裁剪节点ClippingNode

//
//[1].背景图片(Layer层中)
	Sprite* bg = Sprite::create("HelloWorld.png");
	bg->setPosition(visibleSize / 2);
	this->addChild(bg);

//[2].创建裁剪节点 : holesClipper
	holesClipper = ClippingNode::create();
	holesClipper->setPosition(visibleSize / 2);
	this->addChild(holesClipper);

	//属性设置
	holesClipper->setInverted(true);        //倒置显示,未被裁剪下来的剩余部分
	holesClipper->setAlphaThreshold(0.5f);  //设置alpha透明度闸值
	holesClipper->runAction(RepeatForever::create(RotateBy::create(1, 45))); //旋转动作

//[3].创建模板 : holesStencil
	holesStencil = Node::create();
	holesClipper->setStencil(holesStencil); //设置模板节点

	//添加一个模板遮罩 ball
	holesStencil->addChild(Sprite::create("ball.png"), -1);

//[4].创建底板 : holes
	holes = Node::create();
	holesClipper->addChild(holes); //设置底板

	//添加另一个底板内容 blocks
	Sprite* content = Sprite::create("blocks.png");
	holesClipper->addChild(content, -1, "content");

//[5].触摸事件
	auto listener = EventListenerTouchAllAtOnce::create();
	listener->onTouchesBegan = CC_CALLBACK_2(HelloWorld::onTouchesBegan, this);
	_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
//

  1.4、设置触摸事件回调。当触摸点在底板区域内部,则“打洞”

//
void HelloWorld::onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event)
{
//[1].获取触点, 转换为相对holesClipper节点的 相对坐标
	Vec2 point = touches[0]->getLocation();
	point = holesClipper->convertToNodeSpace(point);

//[2].获取底板区域矩形Rect
	Sprite* content = (Sprite*)holesClipper->getChildByName("content");
	Size contentSize = content->getContentSize();
	Rect rect = Rect(-contentSize.width / 2, -contentSize.height / 2, contentSize.width, contentSize.height);

//[3].触摸点在底板内部, 进行"打洞"
	if (rect.containsPoint(point))
	{
		pokeHoleAtPoint(point);
	}
}
//

1.5、实现“打洞”操作函数

//
void HelloWorld::pokeHoleAtPoint(Vec2 point)
{
	CCLOG("Add a Hole!!!");

//[1].添加底板内容 : 一个洞的痕迹
	auto hole = Sprite::create("hole_effect.png");
	hole->setPosition(point);
	holes->addChild(hole);

//[2].添加模板内容 : 一个小洞
	auto holeStencil = Sprite::create("hole_stencil.png");
	holeStencil->setPosition(point);
	holesStencil->addChild(holeStencil);

//[3].动作效果 : 放大缩小
	holesClipper->runAction(Sequence::create(ScaleTo::create(0.05f, 1.05f), ScaleTo::create(0.05f, 1.0f), NULL));
}
//

  1.6、分析与总结

这里设置了倒置显示(Inverted),即使用模板对底板进行裁剪后,显示未被剪下的剩余部分。

(1)模板Stencil:

(2)底板:

(3)裁剪遮罩效果图:

显示未被模板裁剪的剩余部分。

2、“文字遮罩特效”

先来看看效果:

  2.1、素材

    

  2.2、代码实现

//
//[1].背景图片
	Sprite* bg = Sprite::create("HelloWorld.png");
	bg->setPosition(visibleSize / 2);
	this->addChild(bg, -1);

//[2].创建主题文字 : gameTitle
	Sprite* gameTitle = Sprite::create("game_title.png");

	//获取尺寸大小
	Size clipSize = gameTitle->getContentSize();

//[3].创建底板的发光图片 : spark
	Sprite* spark = Sprite::create("spark.png");
	spark->setPosition(-clipSize.width, 0);

//[4].创建裁剪节点 : clippingNode
	ClippingNode* clippingNode = ClippingNode::create();
	clippingNode->setPosition(visibleSize / 2);
	this->addChild(clippingNode);

	clippingNode->setAlphaThreshold(0.05f); //设置alpha闸值
	clippingNode->setContentSize(clipSize); //设置尺寸大小

	clippingNode->setStencil(gameTitle);   //设置模板stencil
	clippingNode->addChild(gameTitle, 1);  //先添加标题,会完全显示出来,因为跟模板一样大小
	clippingNode->addChild(spark,2);       //会被裁减

//[5].左右移动spark
	MoveTo* moveAction = MoveTo::create(2.0f, Vec2(clipSize.width, 0));
	MoveTo* moveBackAction = MoveTo::create(2.0f, Vec2(-clipSize.width, 0));
	spark->runAction(RepeatForever::create(Sequence::create(moveAction, moveBackAction, NULL)));
//

  2.3、分析与总结

实际上就是将文字作为模板Stencil,做出文字的“形状模板”,然后去裁剪底板。

而底板则是由文字、发光棒组合而成,然后移动发光棒,就可以呈现文字发光的效果。

(1)模板Stencil:

(2)底板:

(3)剪裁遮罩效果图:

时间: 2024-08-01 22:39:57

cocos2dx[3.2](19)——裁剪节点ClippingNode的相关文章

cocos2dx 3.2 裁剪节点 ClippingNode

效果1: 效果2: 代码: // //[1].背景图片 Sprite* bg = Sprite::create("HelloWorld.png"); bg->setPosition(visibleSize / 2); this->addChild(bg, -1); //[2].创建主题文字 : gameTitle Sprite* gameTitle = Sprite::create("game_title.png"); //获取尺寸大小 Size cli

cocos2d-x新手引导遮罩CCClippingNode裁剪区域

废话不多说,我直接封装了一个类,是个layer,需要的时候直接添加layer就行  //白白原创 头文件 #pragma once #include "cocos2d.h" USING_NS_CC; const int kTagBackground=0; const int kTagClipNode=1; const int kTagTip=2; class TestLayer : public CCLayer { public: CREATE_FUNC(TestLayer); vir

cocos2dx[3.4](26)——视差节点ParallaxNode

[唠叨] 当我们移动时,我们会看到离我们越近的物体,会移动的越快,越远的物体,比如远处的山会移动的很慢,而最远处的物体,比如太阳几乎不动,这个现象叫视差. 而在游戏中模仿视差,可以让玩家感觉到游戏中的角色的确是在移动.Cocos提供了 ParallaxNode 视差节点类,可以很容易的建立一个视差层,你可以控制每一层的视差率.位置和层级的高低. [参考] http://www.cocoachina.com/bbs/read.php?tid=213748 (无限视差节点+阴影仿真) http://

cocos2dx 2.x 在ios8下clippingNode不起作用 解决办法

升级xcode到6.1后,跑以前的cocos2dx 2.x写的项目,发现clippingNode失效了. 后来看到这个帖子,解决了我的问题:http://discuss.cocos2d-x.org/t/ccclippingnode-will-raise-error-stencil-buffer-is-not-enabled-when-your-apps-first-draw-use-ccclippingnode/17184/2 下面解法引自上帖: [[UIApplication sharedAp

cocos2dx基础篇(19)——音乐音效SimpleAudioEngine

[唠叨] 本节比较简单,主要讲讲cocos2dx引擎中的音乐音效. [致谢] http://gl.paea.cn/contents/f86d1f6e2a52e7ea.html [术语] 单例类:说的通俗一点,它就是一个全局静态类.第一次调用时会创建一个全局静态对象,整个游戏的运行过程中会一直存在,全局都可以访问. [SimpleAudioEngine] 音乐音效是每个游戏中不可或缺的部分,一个好的声音会给玩家留下深刻的印象,当一听到游戏的声音,就会不自觉得说出游戏的名称来.就像<中国好声音>一

Cocos2dx CrazyTetris 双线伪裁剪算面积 对于判断消除的思考(二)

上一篇主要讲了我对裁剪消除算法的思考,这一篇的主题是计算单行覆盖面积,以此来确定是否达到了裁剪条件. 就像之前所说的,在该游戏中,基本方块都由四个小方块构成,四个小方块的尺寸均是25*25.因此游戏区域是宽可容纳10个方块,高可容纳20个方块.即250*500.每行的间距均是25. 因此,现在的问题就是,如何判定在这个宽250,高25的区域内,方块所占的面积.如果能够计算出其面积,而这个区域的总面积为250 * 25 = 6250,那么就可以据此来判断是否满足消除条件.例如:面积 > 6000.

使用ClippingNode对精灵进行遮罩处理

在制作一个消除游戏时,有这样一个情况:方块从顶部往下面掉落,在进入布局前,是不能显示的,不然影响视觉体验.那么,既然此方块已经被加入到渲染树了,那么怎么能让其在一部分中不显示,而在另一部分中显示呢? 这就要用到遮罩处理了.在cocos2d-x中,提供了一个裁剪节点ClippingNode,可以实现一个裁剪效果,那么被裁剪掉的部分,就是等于被遮罩了.可能其效果更多,我未深刻研究,只是拿它用来处理上面的问题.官方对此类的介绍在: http://www.cocos2d-x.org/docs/manua

【Cocos游戏实战】功夫小子第五课之帮助场景和选关功能的实现

功夫小子之帮助场景和选关功能的实现 转载请注明出处:http://blog.csdn.net/suool/article/details/46661231 本节课的视频教程地址是: 第五课在此 如果本教程有帮助到您,希望您能点击进去观看一下,而且现在注册成为极客学院的会员,即日起至7月1日,极客学院的 VIP 课程 30 天免费体验,想学编程的小伙伴速来,只针对新用户:http://e.jikexueyuan.com/invite/index.html?ZnJvbV9jb2RlPVkxblJUZ

节点裁剪 ClippingNode

有时候我们需要一张圆形的图片,可是美术提供的是一个矩形的资源图片,怎么办?让美术再做一张圆形的?即使这样能暂时解决问题,无疑增加了开销,何况有时候你可能需要显示一张图片里的不同部分,不可能每种情况都让美术都做一次修改吧,这时候 cocos2d-x 里提供的节点裁剪技术就派上用场了. 节点裁剪 原理 cocos2d-x 提供 CCClippingNode 类的可以用来对节点进行裁剪,可以根据一个模板切割节点图片,生成任何形状(取决于模板)的节点显示. CCClippingNode 是 CCNode