分享自定义mask挖洞

自定义遮罩挖洞

作者:未生畏死

介绍

  • 关于新手引导和各种层级展示,有时候展现效果会显得很麻烦。所以我查阅大佬们的资料,自己写了一个小脚本。

效果展示

在这里插入图片描述

原理

  • 依赖于cc.Mask组件.将mask组件尺寸归0.选择反向遮罩。基于mask的_graphics通过传入的节点数组进行绘图。
  • 然后有一个子节点bg作为遮盖。在子节点上注册事件处理事件穿透即可。关键属性swallowTouches。

代码展示

···
const { ccclass, property, requireComponent, disallowMultiple, executeInEditMode } = cc._decorator;

@ccclass
//@ts-ignore
@disallowMultiple(false)
// @executeInEditMode()
@requireComponent(cc.Mask)
export default class MaskCut extends cc.Component {
@property(cc.Node)
bg: cc.Node = null;
private mask: cc.Mask = null;
private list: Array<cc.Node> = [];
private _callBack: Function = null;
onEnable() {
this.mask = this.getComponent(cc.Mask);
cc.director.on(“mmask”, this.drawAll, this);
this.bg.on(cc.Node.EventType.TOUCH_START, this.clickStart, this);
this.bg.on(cc.Node.EventType.TOUCH_MOVE, this.clickMove, this);
this.bg.on(cc.Node.EventType.TOUCH_END, this.clcikEnd, this);
this.bg.on(cc.Node.EventType.TOUCH_CANCEL, this.clickCancell, this);
//@ts-ignore
this.bg._touchListener.setSwallowTouches(true);
}
drawAll(arr?: Array<cc.Node>, _callBack?: Function) {
if (!arr) return;
this._callBack = _callBack;
//@ts-ignore
let gr: cc.Graphics = this.mask._graphics;
gr.clear();
this.list = arr;
arr.forEach((ele: cc.Node) => {
this.drawOne(ele, gr);
})
}
drawOne(node: cc.Node, gr: cc.Graphics) {
let wroldPos = node.convertToWorldSpaceAR(cc.v2(0, 0));
let localPos = this.node.convertToNodeSpaceAR(wroldPos);
let x = localPos.x - node.width * node.anchorX * node.scaleX;
let y = localPos.y - node.height * node.anchorY * node.scaleY;
gr.fillRect(x, y, node.width * node.scaleX, node.height * node.scaleY);
}
clickStart(event: cc.Event.EventTouch) {
this.isSwallowTouches(event);
}
clickMove(event: cc.Event.EventTouch) {
this.isSwallowTouches(event);
}
clickCancell(event: cc.Event.EventTouch) {
this.isSwallowTouches(event);
}
clcikEnd() {
//@ts-ignore
let b = this.bg._touchListener.swallowTouches;
console.log(“在吗:”, b)
if (!b) {
//不点遮罩会穿透的哟
// console.log(“干得漂亮”);
} else {
//点遮罩要干点什么吗
// console.log(“点我干嘛”);
if (this._callBack)
this._callBack();
}
}
onDisable() {
cc.director.off(“mmask”, this.drawAll, this);
}
isSwallowTouches(event: cc.Event.EventTouch) {
let b = this.hitTest(event);
if (b) {
//@ts-ignore
this.bg._touchListener.setSwallowTouches(false);
} else {
//@ts-ignore
this.bg._touchListener.setSwallowTouches(true);
}
}
hitTest(event: cc.Event.EventTouch) {
if (this.list == []) return false;
for (let i = 0; i < this.list.length; i++) {
let item = this.list[i];
let b = item.getBoundingBoxToWorld().contains(event.getLocation());
console.log(b);
if (b) return true;
}
return false;
}
}
···

使用方法

  • 发送事件即可 cc.director.emit(“mmask”, this.list, this._maskCall.bind(this));
  • 参数:节点数组,回调方法。
扩展
  • 我是基于事件,发送节点数组。你们可以改成基于子节点节点进行绘制。
  • 可扩展绘制方法,进行圆形,椭圆等绘制。
4赞

大佬流啤,mark一下