参考资料:

http://blog.csdn.net/jackystudio/article/details/17160973

【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)来创建。

1
2
3
4
5
6
7
//
    //创建,不含模板(stencil)
    ClippingNode* clippingNode = ClippingNode::create();
 
    //创建,使用模板(stencil)
    ClippingNode* clippingNode = ClippingNode::create(stencil);
//

3.2、设置模板(Stencil)

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//
/**
 *     用来做裁剪的模板(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)

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

3.4、倒置显示(Inverted)

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

    > true  :显示剩余部分。

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

3.5、alpha阈值(alphaThreshold)

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

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

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

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

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

1
2
3
4
5
//
    //设置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的像素不被绘制,只绘制了一个小圆。


 

具体实例:

1、子弹穿孔
    1.1 创建子弹的ClippingNode
 
HoleClipping.lua

Link: http://codepad.org/jmwuH8CM    [ raw code | fork ]  
HoleClipping=class("HoleClipping",function()
return cc.ClippingNode:create()
end) HoleClipping.ctor=function(self)
self:setInverted(true)
self:setAlphaThreshold(0.5) self.stencil=cc.Node:create()
self.holes=cc.Node:create() self:setStencil(self.stencil)
self:addChild(self.holes)
end --在指定点添加子弹孔
HoleClipping.addHole=function(self,point)
self.rotate=math.random(,)* --旋转角度
self.scale=math.random(,)*0.2+0.9 --缩放 local stencil=function()
local sprite=cc.Sprite:create("Images/hole_stencil.png")
sprite:setPosition(point.x,point.y)
sprite:setScale(self.scale)
sprite:setRotation(self.rotate)
return sprite
end local content=function()
local sprite=cc.Sprite:create("Images/hole_effect.png")
sprite:setPosition(point.x,point.y)
sprite:setScale(self.scale)
sprite:setRotation(self.rotate)
return sprite
end self.holes:addChild(content())
self.stencil:addChild(stencil())
end --添加剪裁内容
HoleClipping.addContent=function(self,content)
self.holes:addChild(content)
end HoleClipping.create=function()
local clip=HoleClipping.new()
return clip
end return HoleClipping
 
Background.lua

Link: http://codepad.org/C13kJ4vP    [ raw code | fork ]
Background=class("Background",function()
return cc.ClippingNode:create()
end) Background.ctor=function(self)
local size=cc.Director:getInstance():getWinSize()
self:setPosition(size.width/,size.height/)
self:setAnchorPoint(0.5,0.5)
local action=cc.RotateBy:create(,)
self:runAction(cc.RepeatForever:create(action)) self:setStencil(self:block())
end --背景图片
Background.block=function(self)
local sprite=cc.Sprite:create()
sprite:setTexture("Images/blocks.png")
sprite:setScale()
return sprite
end Background.create=function()
local sprite=Background.new()
return sprite
end return Background
HoleLayer.lua
Link: http://codepad.org/FZKuKRDS    [ raw code | fork ]
HoleLayer=class("HoleLayer",function()
return cc.LayerColor:create(cc.c4b(,,,))
end) HoleLayer.ctor=function(self)
local function onTouchBegin(touch,event)
if self:onTouchBegin(touch,event) then
return true
end
return false
end local function onTouchMoved(touch,event)
self:onTouchMoved(touch,event)
end local function onTouchEnded(touch,event)
self:onTouchEnded(touch,event)
end
local listener=cc.EventListenerTouchOneByOne:create()
listener:registerScriptHandler(onTouchBegin,cc.Handler.EVENT_TOUCH_BEGAN)
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED)
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED)
local dispacher=cc.Director:getInstance():getEventDispatcher()
dispacher:addEventListenerWithSceneGraphPriority(listener,self) --添加BackgrounClipping
local node=require("sprite/clipping/Background")
self.outerClip=node.create() --添加子弹HoleClip
local hole=require("sprite/clipping/HoleClipping")
self.holeClip=hole.create()
self.holeClip:addContent(self.outerClip:block()) self.outerClip:addChild(self.holeClip)
self:addChild(self.outerClip)
end HoleLayer.onTouchBegin=function(self,touch,event)
cclog("<HoleLayer.onTouchBegin>")
return true
end HoleLayer.onTouchMoved=function(self,touch,event) end HoleLayer.onTouchEnded=function(self,touch,event)
local point=touch:getLocation() --返回的是WordSpace坐标
self.holeClip:addHole(self.holeClip:convertToNodeSpace(point)) --转换成NodeSpace --outerClip特效
local action1=cc.ScaleBy:create(0.05,0.95)
local action2=cc.ScaleTo:create(0.1,)
self.outerClip:runAction(cc.Sequence:create(action1,action2))
end HoleLayer.create=function()
local layer=HoleLayer.new()
return layer
end return HoleLayer
 
执行效果:
    
 
 
2、闪烁字实现
    ClipFont.lua

   [ raw code | fork ]
 

Lua, pasted 2 seconds ago:

ClipFont=class("ClipFont",function() return cc.ClippingNode:create() end) ClipFont.init=function(self) self:setInverted(false) self:setAlphaThreshold(0.5) local size=cc.Director:getInstance():getWinSize() local loadTitle=function() local title=cc.Sprite:create() title:setTexture("clipfont/game_title.png") title:setPosition(size.width/2,size.height/2) return title end local loadSpark=function() local spark=cc.Sprite:create() spark:setTexture("clipfont/spark.png") spark:setAnchorPoint(1,1) spark:setPosition(0,size.height) local move_end=cc.MoveTo:create(1,cc.p(size.width,size.height)) local move_begin=cc.MoveTo:create(1,cc.p(0,size.height)) local seq=cc.Sequence:create(move_end,move_begin) spark:runAction(cc.RepeatForever:create(seq)) return spark end local title=loadTitle() local spark=loadSpark()  self:addChild(title,1) self:addChild(spark,2) self:setStencil(title)  --ClippingNode的模板是特效字 end ClipFont.create=function(self) local node=ClipFont.new() node:init() return node end return ClipFont 

闪烁字效果:

    

3、新手指引
    ClipGuide.lua

Link: http://codepad.org/7ZMoNJz2    [ raw code | fork ]
ClipGuide=class("ClipGuide",function()
return cc.ClippingNode:create()
end) ClipGuide.init=function(self)
local size=cc.Director:getInstance():getWinSize()
local loadTexture=function(texture,position)
local sprite=cc.Sprite:create()
sprite:setTexture(texture)
sprite:setPosition(position.x,position.y)
return sprite
end --模板
local stencilPosition=cc.p(size.width/,size.height/)
local stencil=loadTexture("clipguide/CloseSelected.png",stencilPosition)
local stencilSize=stencil:getBoundingBox()
stencil:setScale(1.5)
self.stencil=stencil --背景图层
local layer=cc.LayerColor:create(cc.c4b(,,,),size.width,size.height) self:setInverted(true)
self:setAlphaThreshold()
self:setStencil(stencil)
self:addChild(layer)
end ClipGuide.getStencilRect=function(self)
local pointX=self.stencil:getPositionX()
local pointY=self.stencil:getPositionY()
local size=self.stencil:getBoundingBox()
return cc.rect(pointX-size.width/,pointY-size.height/,size.width,size.height)
end ClipGuide.create=function(self)
local clip=ClipGuide.new()
clip:init()
return clip
end return ClipGuide
BackLayer.lua

Link: http://codepad.org/P7ZpcqTW    [ raw code | fork ]
BackLayer=class("BackLayer",function()
return cc.Layer:create()
end) BackLayer.ctor=function(self)
local size=cc.Director:getInstance():getWinSize()
self.size=size
local sprite=cc.Sprite:create("clipguide/HelloWorld.png")
sprite:setPosition(size.width/,size.height/)
self:addChild(sprite) --添加ClippingNode遮罩
local clip=require("sprite.clipping.guide.ClipGuide")
self.clip=clip.create()
self:addChild(self.clip) --添加提示标志
self.tip=self:guideSprite()
self:addChild(self.tip) --添加监听事件
self:event()
end BackLayer.guideSprite=function(self)
--提示标志
local guide=cc.Sprite:create()
guide:setTexture("clipguide/tip.png")
guide:setPosition(self.size.width/-,self.size.height/+)
guide:setScale(0.4)
guide:setRotation() --提示标志动作
local scale1=cc.ScaleBy:create(0.25,0.95)
local scale2=cc.ScaleTo:create(0.25,0.4)
local action=cc.Sequence:create(scale1,scale2)
guide:runAction(cc.RepeatForever:create(action)) return guide
end BackLayer.event=function(self)
local function onTouchBegin(touch,event)
return true
end local function onTouchMoved(touch,event)
end local function onTouchEnded(touch,event)
local location=touch:getLocationInView() -- touch in screen
local glPoint=cc.Director:getInstance():convertToGL(location)
if self.clip and self.tip then
local rect=self.clip:getStencilRect()
if cc.rectContainsPoint(rect,glPoint) then
self:removeChild(self.clip,true)
self:removeChild(self.tip,true)
self.clip,self.tip=nil,nil
end
end
end local listener=cc.EventListenerTouchOneByOne:create()
listener:registerScriptHandler(onTouchBegin,cc.Handler.EVENT_TOUCH_BEGAN)
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED)
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED) local dispacher=cc.Director:getInstance():getEventDispatcher()
dispacher:addEventListenerWithSceneGraphPriority(listener,self)
end BackLayer.create=function()
local layer=BackLayer.new()
return layer
end return BackLayer
执行效果:
    

【Cocos2dx 3.3 Lua】剪裁结点ClippingNode的更多相关文章

  1. Cocos2d-x 3.2 Lua演示样本CocosDenshionTest(音频测试)

    Cocos2d-x 3.2 Lua演示样本CocosDenshionTest(音频测试)  本篇博客介绍Cocos2d-x 3.2中Lua演示样例的音频測试.Cocos2d-x使用SimpleAudi ...

  2. Cocos2d-x 3.2 Lua演示样例 ClickAndMoveTest(点击移动測试)

    Cocos2d-x 3.2 Lua演示样例 ClickAndMoveTest(点击移动測试)  本篇博客介绍Cocos2d-x 3.2Lua演示样例中点击移动的样例,在这个样例你能够得到怎样创建单点触 ...

  3. Cocos2d-x 脚本语言Lua中的面向对象

    Cocos2d-x 脚本语言Lua中的面向对象 面向对象不是针对某一门语言,而是一种思想.在面向过程的语言也能够使用面向对象的思想来进行编程. 在Lua中,并没有面向对象的概念存在,没有类的定义和子类 ...

  4. Cocos2d-x 3.2 Lua演示样例 XMLHttpRequestTest(Http网络请求)

    Cocos2d-x 3.2 Lua演示样例 XMLHttpRequestTest(Http网络请求)     本篇博客介绍Cocos2d-x 3.2Lua演示样例中的XMLHttpRequestTes ...

  5. Cocos2d-x 脚本语言Lua使用

    Cocos2d-x 脚本语言Lua使用 前面几篇博客已经把Lua的相关基础知识介绍了.本篇博客就来介绍一下,怎样在Cocos2d-x项目中使用Lua这门脚本语言进行开发.因为笔者使用的时Mac系统.所 ...

  6. 笔记:利用Cocos2dx 3.3 lua 做一个动作类游戏(一)

    在这之前,声明一下: 做不完我是小狗. 没办法,没毅力和恒心,之前的那个Quick Cocos2dx做的横版过关游戏的demo已经转成了3.3的版本了,其实也算是个半成品,战斗,UI啥的都有了,呵呵. ...

  7. 【Cocos2dx 3.3 Lua】滚动字幕

    参考资料:     http://blog.csdn.net/jackystudio/article/details/12991977   1.原理         通过调用update来更新位置达到 ...

  8. 【Cocos2dx 3.3 Lua】定时器事件

    Cocos2dx 3.x Lua 中使用定时器有两种方式: (1)self:scheduleUpdateWithPriorityLua(update, priority) > 参数一:刷新函数 ...

  9. 【Cocos2dx 3.x Lua】TileMap使用

    1.编辑TileMap地图资源 2.Cocos2dx 3.x Lua中使用TileMap   Link: http://codepad.org/P0nFP1Dx  local TileMap=clas ...

随机推荐

  1. 《转》Python学习(14)-对文件的操作(一)

    转自 http://www.cnblogs.com/BeginMan/p/3166644.html 一.文件对象 我理解的文件对象就是一个接口,通过这个接口对文件进行相关操作. <Python ...

  2. mysqlint类型的长度值mysql在建表的时候int类型后的长度代表什么

    详解mysql int类型的长度值 mysql在建表的时候int类型后的长度代表什么 是该列允许存储值的最大宽度吗 为什么我设置成int(1), 也一样能存10,100,1000呢. 当时我虽然知道i ...

  3. WP8.1学习系列(第一章)——添加应用栏

    做过android开发的同学们应该都知道有个ActionBar的头部操作栏,而wp也有类似的一个固定在app页面里通常拥有的内部属性,就是应用栏.以前叫做ApplicationBar,现在wp和win ...

  4. Geoserver

    Geoserver是一个功能齐全,遵循OGC开放标准的开源WFS-T和WMS服务器.利用Geoserver可以把数据作为maps/images来发布(利用WMS来实现)也可以直接发布实际的数据(利用W ...

  5. mysql学习笔记-创建用户以及登录,基本信息查询

    第一天: 创建一个mysql账号:create user ‘新的用户名’@‘localhost’identified by ‘口令’: Now()显示当日日期和时间,user()显示当前的用户,ver ...

  6. C#访问SQLServer数据库访问帮助类

    SQLServer数据库访问帮助类 这里有一个Mysql帮助类的使用例子可以参考(大同小异) 写了一个Mysql的例子,SQLServer的差不多,一样的 C#简单三层结构设计UI.BLL.DAL 1 ...

  7. 题目1446:Head of a Gang(并查集操作)

    题目链接:http://ac.jobdu.com/problem.php?pid=1446 详解链接:https://github.com/zpfbuaa/JobduInCPlusPlus 参考代码: ...

  8. LeetCode 11 Container With Most Water(分支​判断问题)

    题目链接 https://leetcode.com/problems/container-with-most-water/?tab=Description   Problem: 已知n条垂直于x轴的线 ...

  9. XSS 跨站脚本攻击(Cross Site Scripting)

    xss表示Cross Site Scripting(跨站脚本攻击),它与SQL注入攻击类似,SQL注入攻击中以SQL语句作为用户输入,从而达到查询/修改/删除数据的目的,而在xss攻击中,通过插入恶意 ...

  10. Fiddler 教程(转载,鉴于原作者关闭了访问fiddler系列文章)

    阅读目录 Fiddler的基本介绍 Fiddler的工作原理 同类的其它工具 Fiddler如何捕获Firefox的会话 Fiddler如何捕获HTTPS会话 Fiddler的基本界面 Fiddler ...