cocos2d-x CCClippingNode遮罩实现手电筒效果
http://www.firedragonpzy.com.cn/index.php/archives/3810- 作者 firedragonpzy
- 7 七月, 2013
- 13条评论
本文为firedragonpzy原创,转载务必在明显处注明:
转载自【Softeware MyZone】原文链接: http://www.firedragonpzy.com.cn/index.php/archives/3810
Software MyZone:66202765(群号,欢迎加入,若满,请加1群)
Software MyZone 1群(2dx):286504621
【加群请写:Software MyZone或者是firedragonpzy】
淘宝店:【应小心的易淘屋】初次开店,大家多多支持……
群论坛:火龙论坛正试运营阶段,欢迎大家多提些建设性意见……
之前写了一篇文章:cocos2d-x 精灵的移动遮罩[手电筒效果],那个是用的是CCRenderTexture来实现的,今天呢,和大家分享一下如何使用cocos2d-x的新功能:CCClippingNode实现手电筒效果。。。
在开始本文之前,先和大家讨论一下这个遮罩,什么是遮罩动画?
百科是这么解释的:
遮罩动画:运用遮罩制作而成的动画。遮罩层中的内容在动,而被遮罩层中的内容保持静止。
先给大家贴上两张图片有助于理解:
第一张图片呢,上面我也加了必要的解释,第二张小图,是ps的层级关系,贴出来大家看一下。。。
好,开始说遮罩:
这个遮罩动画是有一个遮罩层和一个被遮罩层组成的,其中的遮罩层也就是第一张图片中的漆黑之地,被遮罩层也就是蓝色带着小草的背景。这样你移动遮罩层就能透过手电筒处的透明看见后面的背景了。这时候,或许有人就问这样不是手电筒效果啊?遮罩层直接动的。。。是,是不能实现,这个先不急,我先和大家分析下这个遮罩怎么和我们2dx中的CCClippingNode结合起来,完后呢,再解释这个问题。
在CCClipingNode的创建使用中,它是需要两个参数的,一个是stencil,也就是mask(遮罩节点),一个是content,也就是遮罩内容。关于遮罩节点,就是手电筒效果的黑色图片,遮罩内容:content,也就是阶梯形状的图形。
在这里很多东西容易混淆,我就是在这里晕了,2了,才让我公司的方哥给我讲了好几遍,因为当时我们的思维不在一条现在,理解什么的不对头。
在这里和大家针对上面的讲解再整理一下思路。
遮罩动画由遮罩层和被遮罩层组成,遮罩层移动,显示出特殊的效果。而遮罩动画关联到我们的2dx中,遮罩层就是我们的CCClippingNode,它创建时候需要的stencil就是第二个图片中,第一个层手电筒层的第二个图形,它需要的content就是第一个层的第一个图形。
也就是说,我们需要完成我们的场景:小猪进入山洞,开启手电筒照明。我们需要一个背景图作为被遮罩层,一个CCClippingNode制作的节点作为遮罩层。在这里制作这个场景千万不要把CCClippingNode的content作为被遮罩层,stencil作为遮罩层。我就是犯了这个错误,才导致实现不了效果的。其实从前文第二张图片中我们也可以清晰的看出遮罩动画的组成:两个层:手电筒作为遮罩层在被遮罩层(背景层)的上面。手电筒层由两个图组成,自左向右为遮罩内容和遮罩节点。
想必,讲到这里,大家应该明白了什么是遮罩动画,遮罩动画和2dx中的CCCLipingNode是怎么结合起来的。接下来我们再讲解一下这个实现手电筒思路的问题。
使用CCClippingNode,我是先学习了2dx自带的例子,三角形遮罩主角的那个。简单贴一下代码便于讲解,后期我会把例子直接上我的github:
123456 | void
//设置clipper CCClippingNode* //得到clipper CCNode* //设置遮罩节点 CCDrawNode* //设置遮罩形状,其实也就是遮罩节点 CCNode* //设置遮罩内容 void
float
//更新遮罩节点位置 |
我实现手电筒效果是让手电筒作为遮罩节点,黑色layer作为遮罩内容。但是出来的手电筒效果很死板,没有渐变的效果。关于遮罩节点的获取是__getMaskStencil(),也就是__getMaskShape(),代码如下;
1234567891011121314151617181920 | CCNode* { stencil return
} CCDrawNode* { CCDrawNode CCPoint vertext4[0] vertext4[1] vertext4[2] vertext4[3] ccColor4F shape->drawPolygon(vertext4, return
} |
这个出来的是个四边形,把这个四边形绑定到主角上跟随主角,就产生了手电筒效果。在这里说明一下CSArmature的实例目前是不支持添加Child的【CSArmature:0.1.4】,所以产生了我的__updateStencilPos方法。好了,大功告成,一个手电筒效果就出来了,效果大家可以看后期上传的demo。
在这里在简单解释一下这个原理:
学过ps的同胞们可能知道,黑色代表透明,也就是显示出被遮罩层的东西来,联系到我们2dx中,我的mask是CCDrawNode的一个实例,是画出来的,默认为黑色,正好凸显出背景的颜色。简单的理解,相当于从背景上扣出来我mask的形状。
再深入一下,从ps中来阐述:
在遮罩层中,mask(也就是第一张图中的手电筒)的黑色区域代表隐藏,白色区域代表显示。它这里的隐藏是隐藏content的,不要和被遮罩层(也就是第一张图中的背景)联系起来。这样子产生的效果就是我们第一张图中阶梯状的黑色图形,中间扣除了一个手电筒效果。而平时我们说的黑色代表透明,这个是针对遮罩层中的mask和被遮罩层来说的。mask中的黑色区域透明,显示出被遮罩层的物体,效果就是第一张图,在蓝色的背景之上有一个黑色的阶梯形状的图片。好,就简单说到这里,我们继续之前的问题。
悲剧的是虽然有了手电筒效果,但是显得非常的死板,没有光晕,就是一个生硬的形状,而且还有锯齿,悲剧……
出现这个效果,我想啊,想啊,认为这个CCClippingNode是不能实现我们需要的渐变效果的……
在这里,大家可以考虑下,我们的mask是不能制作出渐变的效果的,或许有些朋友不这么认为,说你是用CCDrawNode画出来的图形,你可以用一张渐变的图片作为mask啊,那不就有渐变效果了啊。答案是否定的,CCClippingNode中有个设置透明镂空的方法,clipper->setAlphaThreshold(0.05f);默认值是1.0f,它根据你设置的值进行裁剪,这会导致你渐变的出现锯齿,但是绝对不会出现你想要的渐变效果。那是不是CCClippingNode确实不能实现这个效果了呢。作为程序的我已经确定了,不能实现手电筒渐变效果。
不幸的是,它,可以实现手电筒渐变的效果,这里我们直说遮罩层,这时候我们把手电筒效果作为遮罩内容,阶梯形状的图片作为遮罩节点。就是第一张图片中的手电筒层,这样子不就实现了吗?白色代表显示,它显示我们遮罩内容,也就是有手电筒效果的png,png为渐变镂空的手电筒效果和黑色背景组成。或许到这里还有同胞不明白,我再啰嗦一下,之前我们提及:mask的黑色代表透明,也就是显示被遮罩内容,我们的阶梯形状的图片,右下角是白色的,拿到被遮罩层应该是不显示的,显示的会是我们的遮罩层中的遮罩内容,但是这里我们的遮罩内容是一个透明渐变的手电筒效果,所以可以显示我们被遮罩的内容,导致最终出现了带有渐变的手电筒效果。这个,你,想到了吗?
哎,我是不是真笨了,这个怎么没有想到呢?哎,在这里对公司的方哥表示万分的感谢,是他在炎热的夏天不厌其烦的给我讲解的,虽然是后期自己搞明白的【当时主要是我们的思维不在一条线上,概念性的东西不大明确,些许带有程序员的思维定势】,但是在炎热的夏天能给一个人讲解一个问题到4遍,已经很令人佩服了,要是我,给人讲解3遍就烦了。
好了,就到这里把……希望对大家有帮助,也欢迎大神拍砖……
PS:这篇博文是本周末最有意义的事情了吧,呵呵……
Demo链接:https://github.com/firedragonpzy/ClippingNodeDemoSelf.git