【Cocos2dx 3.3 Lua】剪裁結點ClippingNode

參考資料:

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

 

【ClippingNode】dom

一、原理ide

    ClippingNode(裁剪節點)能夠用來對節點進行裁剪。ClippingNode是Node的子類,能夠像普通節點同樣放入Layer,Scene,Node中。函數

    主要是根據一個模板(Stencil)切割圖片的節點,生成任何形狀的節點顯示。測試

    ClippingNode是利用模板遮罩來完成對Node區域裁剪的技術。ui

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

wKiom1Q2LVXAUAoEAACGmnfvB2U591.jpg

 

二、舉例說明spa

    模板(Stencil):可使用Layer、Node、Sprite等。.net

    底板           :可使用Layer、Node、Sprite等。3d

    Layer層

 

  2.一、第一組(Layer層無背景圖片)

    > 模板(Stencil):模板爲Node節點,放入5個Sprite的小球

    > 底板           :底板爲Node節點,放入1個Sprite的ABCD圖

    > Layer層        :無元素,背景顏色爲黑色

wKioL1Q2Po3BRAGQAAA0HQ88DTw552.jpg            wKiom1Q2PlXB8lS9AABDigaXvj0088.jpg

 

    > 裁剪遮罩效果示意圖:

    wKioL1Q2QaHgGl_MAAAqz_2tsso946.jpg

 

  2.二、第二組(Layer層有背景圖片)

    > 模板(Stencil):模板爲Node節點,放入5個Sprite的小球

    > 底板           :底板爲Node節點,放入1個Sprite的ABCD圖

    > Layer層        :有一個Sprite的cocos2dx背景圖片

wKioL1Q2QFjTWjVzAAA0HQ88DTw670.jpg            wKioL1Q3cdTioMMRAABDigaXvj0272.jpg

 

wKiom1Q2QCDzGsnXAAFHbk8yBjQ276.jpg

    

    > 裁剪遮罩效果示意圖:

wKiom1Q2QdOz9Uz_AAFU71cfm4M930.jpg

 

  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 )。

    wKiom1Q2UjvQHtewAAALmrZIcP4953.jpg

    (1)在不設置AlphaThreshold閘值或者setAlphaThreshold(1.0f),的狀況下:

    wKioL1Q2U-CyKJR5AABse9r4z7I334.jpg

 

    (2)在設置setAlphaThreshold(0.5f),的狀況下:

    wKiom1Q2U6iTDl2eAABkCos2yS8384.jpg

    (3)結論:

        > 能夠發如今不設置alpha閘值時,模板繪製的區域爲一個40*40的矩形。

        > 設置了alpha閘值爲0.5時,透明度alpha爲0的像素不被繪製,只繪製了一個小圓。

 


 

具體實例:

一、子彈穿孔
    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(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.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/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.lua
Link: http://codepad.org/FZKuKRDS     [ raw code | fork ]
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

 

 
執行效果:
    
 
 
二、閃爍字實現
    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 
閃爍字效果:
    

三、新手指引
    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/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.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/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

 

執行效果:
    
相關文章
相關標籤/搜索