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

  • 相关阅读:
    测试心得
    mysql学习整理
    测试思考
    Win7下安装Mysql方法
    xcall.sh
    hive 的几款可视化连接工具
    mongo 使用 mongoexport 按照条件导出 csv 文件
    WebFlux springboot 2.0
    Calendar java  日历(常用小结)
    java 自定义注解(3)
  • 原文地址:https://www.cnblogs.com/luosongchao/p/4339533.html
Copyright © 2011-2022 走看看