http://blog.csdn.net/jackystudio/article/details/17160973node
【ClippingNode】dom
一、原理ide
ClippingNode(裁剪節點)能夠用來對節點進行裁剪。ClippingNode是Node的子類,能夠像普通節點同樣放入Layer,Scene,Node中。函數
主要是根據一個模板(Stencil)切割圖片的節點,生成任何形狀的節點顯示。測試
ClippingNode是利用模板遮罩來完成對Node區域裁剪的技術。ui
如何理解ClippingNode的遮罩?看下圖的例子吧。lua
二、舉例說明spa
> 模板(Stencil):可使用Layer、Node、Sprite等。.net
> 底板 :可使用Layer、Node、Sprite等。3d
> Layer層
2.一、第一組(Layer層無背景圖片)
> 模板(Stencil):模板爲Node節點,放入5個Sprite的小球。
> 底板 :底板爲Node節點,放入1個Sprite的ABCD圖。
> Layer層 :無元素,背景顏色爲黑色。
> 裁剪遮罩效果示意圖:
2.二、第二組(Layer層有背景圖片)
> 模板(Stencil):模板爲Node節點,放入5個Sprite的小球。
> 底板 :底板爲Node節點,放入1個Sprite的ABCD圖。
> Layer層 :有一個Sprite的cocos2dx背景圖片。
> 裁剪遮罩效果示意圖:
2.三、分析總結
經過ClippingNode進行裁剪遮罩,實際上是這樣的:
> 將模板(Stencil)上全部元素的形狀集合做爲「形狀模板」,其元素自己不渲染。
> 使用「形狀模板」對底板進行裁剪。
> 顯示從底板上裁剪下來的圖片區域。
總的來講:
> 模板(Stencil)至關因而一個樣板,上面有不少不一樣形狀的"洞洞"。
> 而後根據樣板,對底板進行裁剪,"挖洞"。
> 而後將剪下來的那些碎片,按照原來的位置進行擺放。
其中:模板(Stencil)只是一個「形狀模板」,自己的圖片是不進行繪製的。
三、主要函數
ClippingNode繼承於Node類,用於節點的裁剪與遮罩。
3.一、建立ClippingNode
兩種方式:是否使用模板(stencil)來建立。
1
2
3
4
5
6
7
|
//
//建立,不含模板(stencil)
ClippingNode* clippingNode = ClippingNode::create();
//建立,使用模板(stencil)
ClippingNode* clippingNode = ClippingNode::create(stencil);
//
|
3.二、設置模板(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.三、設置底板(Content)
1
2
3
4
|
//
//建立ClippingNode後,使用addChild()添加的節點,即爲底板內容
clippingNode->addChild(content);
//設置底板
//
|
3.四、倒置顯示(Inverted)
> false :顯示被模板裁剪下來的底板內容。默認爲false。
> true :顯示剩餘部分。
1
2
3
4
5
|
//
//默認爲false
//表示顯示被裁剪下來的底板內容
clippingNode->setInverted(
false
);
//
|
3.五、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的像素不被繪製,只繪製了一個小圓。
具體實例:
|
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(0,1)*360 --旋轉角度 self.scale=math.random(0,1)*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=class("Background",function() return cc.ClippingNode:create() end) Background.ctor=function(self) local size=cc.Director:getInstance():getWinSize() self:setPosition(size.width/2,size.height/2) self:setAnchorPoint(0.5,0.5) local action=cc.RotateBy:create(1,90) 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(3) return sprite end Background.create=function() local sprite=Background.new() return sprite end return Background
HoleLayer=class("HoleLayer",function() return cc.LayerColor:create(cc.c4b(0,60,30,255)) 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,1) self.outerClip:runAction(cc.Sequence:create(action1,action2)) end HoleLayer.create=function() local layer=HoleLayer.new() return layer end return HoleLayer
Lua, pasted 2 seconds ago:
|
|
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/2,size.height/2) 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(0,0,0,200),size.width,size.height) self:setInverted(true) self:setAlphaThreshold(1) 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/2,pointY-size.height/2,size.width,size.height) end ClipGuide.create=function(self) local clip=ClipGuide.new() clip:init() return clip end return ClipGuide
|
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/2,size.height/2) 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/2-55,self.size.height/2+40) guide:setScale(0.4) guide:setRotation(60) --提示標誌動做 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