一.基本定义
ClippingNode(裁剪节点)可以用来对节点进行裁剪,可以根据一个模板切割图片的节点,生成任何形状的节点显示。ClippingNode是利用模板遮罩来完成对Node区域裁剪的技术。
原理图:
二.上手实例
游戏中,新手引导算是一个比较重要的部分,指引玩家一步步了解游戏,深入游戏,作用相当于老司机啊,告诉我们正确的打开方式。
引导的实现一般分为两步:
- 把背景置灰,把要操作的区域高亮。
- 屏蔽所有的触摸,只能触摸高亮区域。
下面拿我们游戏中的代码做一下演示:
//-------------------1.只显示高亮区域-------------------//
//获取需要高亮的控件
that.rootNode = ccs.load("res/ArenaMain.json").node;
that.addChild(that.rootNode);
var btn_change = that.seekWidgetByName(that.rootNode,"btn_change")
that.widget = btn_change
//创建裁剪节点
var clipNode = new cc.ClippingNode()
that.addChild(clipNode)
//创建底板,将屏幕遮灰
that.layerBg = new cc.LayerColor(cc.color(0, 0, 0, 150))
clipNode.addChild(that.layerBg)
clipNode.setInverted(true)//设置底板可见
//创建模板
var sentcil = new cc.LayerColor(cc.color(255, 255, 255, 100))
clipNode.setStencil(sentcil)//设置裁剪模板
var worldPosition = btn_change.getParent().convertToWorldSpace(btn_change.getPosition())
sentcil.setPosition(worldPosition)
sentcil.ignoreAnchorPointForPosition(btn_change.isIgnoreAnchorPointForPosition())
sentcil.setContentSize(btn_change.getContentSize())
sentcil.setAnchorPoint(btn_change.getAnchorPoint())
//-------------------------------------------------------//
效果图:
//-------------------2.只能触摸高亮区域-------------------//
var listener = cc.EventListener.create({
event: cc.EventListener.TOUCH_ONE_BY_ONE,
swallowTouches: true,
onTouchBegan: function (touch, event) {
if(that.widget){
//如果触摸点位于高亮区域,则可向下传递触摸,否则吞噬掉触摸
var isHit = that.widget.hitTest(touch.getLocation())
if(isHit){
listener.setSwallowTouches(false)
}else{
listener.setSwallowTouches(true)
}
}
//cc.log("wade setTouch 111")
return true;
},
onTouchMoved:function (touch, event){},
onTouchEnded:function (touch, event){
},
onTouchCancelled:function (touch, event){
}
})
cc.eventManager.addListener(listener, that.layerBg)
//-------------------------------------------------------//
三.深入研究
1.举例:小球透视
模板:Node节点,放入4个Sprite的小球 。
底板:Node节点,放入1个Sprite的Logo图。
背景:一个Sprite的温馨场景图。
代码实现:
//创建最底层的温馨场景图
this.sprite = new cc.Sprite("res/bg1.jpg")
this.sprite.attr({
x: cc.winSize.width / 2,
y: cc.winSize.height / 2,
})
this.addChild(this.sprite)
//创建裁剪节点
var clipNode = new cc.ClippingNode()
clipNode.attr({
x: 0,
y: 0,
anchorX : 0,
anchorY : 0,
})
this.addChild(clipNode)
//设置alpha阈值
clipNode.setAlphaThreshold(0.05)
//创建底板
var content = new cc.Sprite("res/powered.png")
content.attr({
x: cc.winSize.width/2,
y: cc.winSize.height/2,
anchorX : 0.5,
anchorY : 0.5,
})
clipNode.addChild(content)
//底板可见
clipNode.setInverted(true)
//创建模板
var ball1 = new cc.Sprite("res/SpookyPeas.png")
var ball2 = new cc.Sprite("res/SpookyPeas.png")
var ball3 = new cc.Sprite("res/SpookyPeas.png")
var ball4 = new cc.Sprite("res/SpookyPeas.png")
ball1.setPosition(cc.winSize.width/2-40,cc.winSize.height/2-40)
ball2.setPosition(cc.winSize.width/2+40,cc.winSize.height/2-40)
ball3.setPosition(cc.winSize.width/2-40,cc.winSize.height/2+40)
ball4.setPosition(cc.winSize.width/2+40,cc.winSize.height/2+40)
var sentcil = new cc.Node()
sentcil.attr({
anchorX : 0,
anchorY : 0,
})
sentcil.addChild(ball1)
sentcil.addChild(ball2)
sentcil.addChild(ball3)
sentcil.addChild(ball4)
clipNode.setStencil(sentcil)
效果展示:
分析总结:
通过ClippingNode进行裁剪遮罩,其实是这样的:
将模板(Stencil)上所有元素的形状集合作为 “形状模板” ,其元素本身不渲染。
使用“形状模板”对底板进行裁剪。
显示从底板上裁剪下来的图片区域。
主要函数:
倒置显示(Inverted)
false :显示被模板裁剪下来的底板内容。默认为false。
true :显示剩余部分。
clipNode.setInverted(false)
alpha阈值(alphaThreshold)
alpha:表示像素的透明度值。
只有模板(stencil)中像素的alpha值大于alpha阈值时,内容才会被绘制。alpha阈值(alphaThreshold) :取值范围 [0,1] 。
默认为 1 ,表示alpha测试默认关闭,即全部绘制。
若不是1 ,表示只绘制模板中,alpha像素大于alphaThreshold的内容。
具体说明:
以下是一张 40*40 的图片,其中小球以外的其他区域像素为透明的(即: alpha为 0 )。
(1)在 不设置AlphaThreshold闸值 , 或者 setAlphaThreshold(1.0f) ,的情况下:
(2)在 设置setAlphaThreshold(0.5f) ,的情况下:
结论:
可以发现在不设置alpha闸值时,模板绘制的区域为一个40*40的矩形。
设置了alpha闸值为0.5时,透明度alpha为0的像素不被绘制,只绘制了一个小圆。