zoukankan      html  css  js  c++  java
  • 【Cocos2dx 3.3 Lua】剪裁结点ClippingNode

    参考资料:

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

    【ClippingNode】

    1、原理

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

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

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

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

    wKiom1Q2LVXAUAoEAACGmnfvB2U591.jpg

    2、举例说明

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

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

        Layer层

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

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

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

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

    wKioL1Q2Po3BRAGQAAA0HQ88DTw552.jpg            wKiom1Q2PlXB8lS9AABDigaXvj0088.jpg

        > 裁剪遮罩效果示意图:

        wKioL1Q2QaHgGl_MAAAqz_2tsso946.jpg

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

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

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

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

    wKioL1Q2QFjTWjVzAAA0HQ88DTw670.jpg            wKioL1Q3cdTioMMRAABDigaXvj0272.jpg

    wKiom1Q2QCDzGsnXAAFHbk8yBjQ276.jpg

        

        > 裁剪遮罩效果示意图:

    wKiom1Q2QdOz9Uz_AAFU71cfm4M930.jpg

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

        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.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
     
    执行效果:
        
     
     
    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/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
    执行效果:
        

  • 相关阅读:
    jsp 特殊标签
    poj 1753 Flip Game 高斯消元 异或方程组 求最值
    zoj 3155 Street Lamp 高斯消元 异或方程组 求方案数
    poj1222 EXTENDED LIGHTS OUT 高斯消元解异或方程组 模板
    zoj 3930 Dice Notation 模拟
    zoj 3157 Weapon 线段树求逆序对数
    hdu 1242 Rescue BFS+优先队列
    hdu 3466 Proud Merchants 贪心+01背包
    zoj 3689 Digging 贪心+01背包
    hdu 2602 Bone Collector 01背包模板
  • 原文地址:https://www.cnblogs.com/luosongchao/p/4339533.html
Copyright © 2011-2022 走看看