【Cocos2dx 3.3 Lua】剪裁结点ClippingNode

参考资料:

http://shahdza.blog.51cto.com/2410787/1561937

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(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


Link: http://codepad.org/gYufliIO

raw code | fork ]

 

Lua, pasted 2 seconds ago:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 

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

执行效果:

时间: 2024-11-05 06:13:46

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

Cocos2d-x 3.2 Lua示例CocosDenshionTest(音频测试)

Cocos2d-x 3.2 Lua示例CocosDenshionTest(音频测试) 本篇博客介绍Cocos2d-x 3.2中Lua示例的音频测试,Cocos2d-x使用SimpleAudioEngine这个类来实现音频的控制,比如播放.暂停.停止等操作. Lua代码中,使用的是AudioEngine,具体实现可以参考AudioEngine.lua文件,只是把SimpleAudioEngin进行了封装. 示例代码: --[[ CocosDenshionTest.lua Cocos2d-x 音频支

Cocos2d-x 3.2 Lua示例 CaptureScreen(截屏)

Cocos2d-x 3.2 Lua示例 CaptureScreen(截屏) 转载请注明:IT_xiao小巫 Cocos2d-x截屏功能是从3.2开始提供的,本篇博客就是介绍Cocos2d-x 3.2中Lua示例中的截屏功能.效果如下所示: 例子代码如下: --[[ 截屏测试 CaptureScreenTest ]]-- -- 获取屏幕大小 local winSize = cc.Director:getInstance():getWinSize() local kTagSprite = 1 loc

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

Cocos2d-x 脚本语言Lua中的面向对象 面向对象不是针对某一门语言,而是一种思想.在面向过程的语言也能够使用面向对象的思想来进行编程. 在Lua中,并没有面向对象的概念存在,没有类的定义和子类的定义.但相同在Lua中能够利用面向对象的思想来实现面向对象的类继承. 一.复制表的方式面向对象 --Lua中的面向对象 --[[ 复制表方式面向对象 參数为一张表.通过遍历这张表取值,赋给一张空表,最后返回新建的表.来达到克隆表 ]] function clone(tab) local ins =

Cocos2d-x 3.2 Lua示例 ClickAndMoveTest(点击移动测试)

Cocos2d-x 3.2 Lua示例 ClickAndMoveTest(点击移动测试) 本篇博客介绍Cocos2d-x 3.2Lua示例中点击移动的例子,在这个例子你可以得到如何创建单点触摸的事件和注册事件监听回调方法. 示例代码: --[[ ClickAndMoveTest.lua 点击与移动 ]]-- -- 获取屏幕尺寸 local size = cc.Director:getInstance():getWinSize() local layer = nil -- 层 local kTag

(原创)cocos2d-x 3.0+ lua 学习和工作(2) : 单一继承简单介绍

-- 星月相随倾心贡献~~~ -- 本章简单介绍一下:单一继承 -- 多继承本人还没有用过,主要是lua多继承感觉不好用~~~个人感觉~~~大汗~! -- example: local Base = class( "Base" ) Base.__index = Base function Base:ctor(...) print( self.__cname ) -- 输出:类名字.class( "xxx" ), self._cname 就是 xxx end func

Cocos2d-x 脚本语言Lua基本数据结构-表(table)

table是Lua中唯一的数据结构,其他语言所提供的数据结构,如:arrays.records.lists.queues.sets等,Lua都是通过table来实现,并且在lua中table很好的实现了这些数据结构.--摘自:<Programming in Lua> 看以下代码,可以很清晰的明白Lua中表的使用: -- Lua中的表,table Config = {hello="Hello Lua",world="World"} -- 赋值方式1,以键=

Cocos2d-x 3.2 Lua演示样本 ActionTest(操作测试)

Cocos2d-x 3.2 Lua演示样本 ActionTest(操作测试) 2014年博文大赛,请投上您宝贵的一票:http://vote.blog.csdn.net/Article/Details?articleid=38272837 移动开发狂热者群: 299402133,欢迎广大开发人员增加 Cocos2d-x官方真够给力的,3.1.1还没有熟悉完,3.2就出来.本篇博客继续介绍Cocos2d-x的Lua演示样例.关于3.2的样例变动不是非常大,略微介绍一下3.2的新特性吧: 3.2版本

(原创) cocos2d-x 3.0+ lua 学习和工作(4) : 公共函数(5): 返回指定表格中的所有键(key):table.keys

这里的函数主要用来做:返回指定表格中所有的键.参考资料为quick_cocos. 星月倾心贡献~~~ --[[ -- 返回指定表格中的所有键(key) -- example: local t = ( a = 1, b = 2, c = 3 ) local keys = table.keys( t ) -- keys = { "a", "b", "c" } -- @param t 要检查的表格(t表示是table) -- @param table

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

在这之前,声明一下: 做不完我是小狗. 没办法,没毅力和恒心,之前的那个Quick Cocos2dx做的横版过关游戏的demo已经转成了3.3的版本了,其实也算是个半成品,战斗,UI啥的都有了,呵呵. 本次DEMO要达成的目的如下: 1 熟悉Cocos2dx 3.3 - lua 2 使用Joystick 3 完成简单的怪物AI 4 尝试扩展现有的api(可选) 嗯,差不多就以上了. 今天第一次笔记. 当前完成的任务有如下: 1 使用新的player新建项目 2 在场景中添加Sprite以及其帧动