消消方块阵换皮表情
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

290 lines
9.6 KiB

1 week ago
//*********************
// create by 流云
// time: Thu Nov 13 2025
// desc:
//*********************
import { _decorator, Node, EventTouch, UITransform, tween, Mask, Graphics, Color } from 'cc';
import { Auto_NewGuideMask } from './Auto_NewGuideMask';
import MTools from 'db://assets/mx/tools/MTools';
const { ccclass, property } = _decorator;
@ccclass('UINewGuideMask')
export class UINewGuideMask extends Auto_NewGuideMask {
registNode = null
graphics = null
finishCallBack = null
nodeArray: Node[] = [];
labArray: string[] = [];
isPlayAnim = true
blackOpacity = 255
//不需要点击拦截
hideSpineshouzhi = true
/** 镂空圆角半径(像素),不超过短边一半 */
holeCornerRadius = 18
/** 边缘虚化描边最大宽度 */
holeFeatherMaxLine = 5
/** 虚化层数 */
holeFeatherLayers = 8
_holeBorderGraphics: Graphics = null
onLoad(): void {
super.onLoad();
}
onEnable(): void {
super.onEnable();
}
onDisable(): void {
super.onDisable();
}
bindNode() {
this.node.on(Node.EventType.TOUCH_START, (event:EventTouch) => {
//目标节点不存在,拦截
if (!this.registNode || this.registNode.isValid == false) {
// this.node['_touchListener'].setSwallowTouches(true);
event.preventSwallow = true;
event.propagationStopped = true;
if(this.registNode && this.registNode.isValid == false){
this.close()
}
return;
}
//目标区域存在,击中放行
let rect = this.registNode.getComponent(UITransform).getBoundingBoxToWorld();
if ( rect.contains(event.getUILocation()) ) {
// this.node['_touchListener'].setSwallowTouches(false);
// 命中镂空区域:不拦截,让触摸继续传给底层按钮
event.preventSwallow = true;
event.propagationStopped = false;
} else {
// this.node['_touchListener'].setSwallowTouches(true);
// 命中非目标区域:拦截,避免误触底层
event.preventSwallow = true;
event.propagationStopped = true;
}
}, this);
//监听事件
this.node.on(Node.EventType.TOUCH_END, (event) => {
//目标节点不存在,拦截
if (!this.registNode || this.registNode.isValid == false) {
// this.node['_touchListener'].setSwallowTouches(true);
event.preventSwallow = true;
event.propagationStopped = true;
if(this.registNode && this.registNode.isValid == false){
this.close()
}
return;
}
//目标区域存在,击中放行
let rect = this.registNode.getComponent(UITransform).getBoundingBoxToWorld();
if ( rect.contains(event.getUILocation()) ) {
// this.node['_touchListener'].setSwallowTouches(false);
// 命中镂空区域:不拦截,让触摸继续传给底层按钮
event.preventSwallow = true;
event.propagationStopped = false;
} else {
// this.node['_touchListener'].setSwallowTouches(true);
// 命中非目标区域:拦截,避免误触底层
event.preventSwallow = true;
event.propagationStopped = true;
}
//目标区域存在,击中放行
if ( rect.contains(event.getUILocation())) {
// 先让底层按钮/节点吃到本次 TOUCH_END,再执行引导回调与切换/关闭
this.scheduleOnce(() => {
this.registNode = null
if (this.finishCallBack) {
this.finishCallBack()
}
if (this.nodeArray.length == 0) {
this.close()
//EventMgr.emitEvent_custom(ryw_Event.swallowToucheFinishEvent);
} else {
let nextNode = this.nodeArray.shift()
this.nextNode(nextNode)
}
}, 0);
//EventMgr.emitEvent_custom(ryw_Event.swallowToucheEvent);
} else {
}
}, this);
}
nextNode(registNode){
this.registNode = registNode
let str = this.labArray.shift()
let posi = MTools.getNodeToTargetPos(this.shouzhiNode, registNode)
if(this.isPlayAnim && this.shouzhiNode.active) {
// this.shouzhiNode.setPosition(0, 0)
tween(this.shouzhiNode)
.to(0.6, {x:posi.x, y:posi.y-5})
.call(()=>{
this._focusToNode(registNode)
if(str && str != ''){
this.guideNode.active = true
this.guideDesc.string = str
}else{
this.guideNode.active = false
}
})
.start()
}else{
this.shouzhiNode.setPosition(posi.x+50, posi.y)
this._focusToNode(registNode)
if(str && str != ''){
this.guideNode.active = true
this.guideDesc.string = str
}else{
this.guideNode.active = false
}
}
}
_ensureHoleBorderGraphics(): Graphics {
if (this._holeBorderGraphics && this._holeBorderGraphics.isValid) {
return this._holeBorderGraphics
}
let borderNode = this.maskNode.node.getChildByName('holeBorder')
if (!borderNode) {
borderNode = new Node('holeBorder')
const ut = borderNode.addComponent(UITransform)
ut.setAnchorPoint(0.5, 0.5)
ut.setContentSize(1, 1)
borderNode.setParent(this.maskNode.node)
borderNode.setSiblingIndex(0)
}
this._holeBorderGraphics = borderNode.getComponent(Graphics) || borderNode.addComponent(Graphics)
return this._holeBorderGraphics
}
/** 与引擎 Mask GRAPHICS_RECT 一致的局部坐标原点(考虑锚点) */
_maskLocalRectOrigin(w: number, h: number): { x: number, y: number } {
const ap = this.maskNode.node.getComponent(UITransform).anchorPoint
return { x: -w * ap.x, y: -h * ap.y }
}
_redrawHoleStencil(w: number, h: number, radius: number) {
const g = this.graphics as Graphics
if (!g) {
return
}
const { x, y } = this._maskLocalRectOrigin(w, h)
const r = Math.min(radius, Math.min(w, h) * 0.5 - 0.5)
g.clear()
g.fillColor = new Color(255, 255, 255, 0)
g.roundRect(x, y, w, h, Math.max(0, r))
g.fill()
}
_drawHoleBorderFeather(w: number, h: number, radius: number) {
const g = this._ensureHoleBorderGraphics()
const { x, y } = this._maskLocalRectOrigin(w, h)
const r = Math.min(radius, Math.min(w, h) * 0.5 - 0.5)
g.clear()
g.lineJoin = Graphics.LineJoin.ROUND
g.lineCap = Graphics.LineCap.ROUND
const layers = Math.max(1, this.holeFeatherLayers)
const maxLw = Math.max(1, this.holeFeatherMaxLine)
for (let i = layers; i >= 1; i--) {
const t = i / layers
const lw = 1 + (maxLw - 1) * t
const a = Math.floor(40 * (1 - t * 0.88))
g.lineWidth = lw
g.strokeColor = new Color(200, 245, 255, a)
g.roundRect(x, y, w, h, Math.max(0, r))
g.stroke()
}
}
_focusToNode(node) {
this.scheduleOnce(() => {
let rect = node.getComponent(UITransform).getBoundingBoxToWorld();
this.maskNode.node.getComponent(UITransform).setContentSize(0,0)
let p = this.node.getComponent(UITransform).convertToNodeSpaceAR(rect.origin);
rect.x = p.x;
rect.y = p.y;
MTools.setNodeToTargetPos(this.maskNode.node, node)
const pad = 20
const w = rect.width + pad
const h = rect.height + pad
this.maskNode.node.getComponent(UITransform).setContentSize(w, h)
const rr = Math.min(this.holeCornerRadius, Math.min(w, h) * 0.12)
this._redrawHoleStencil(w, h, rr)
this._drawHoleBorderFeather(w, h, rr)
})
}
onInit(): void {
// finishCallBack = null
// nodeArray: Node[] = [];
// labArray: string[] = [];
// isPlayAnim = true
// blackOpacity = 255
this.maskNode.type = Mask.Type.GRAPHICS_STENCIL
this.graphics = this.maskNode.node.getComponent(Graphics)
this.nodeArray = this.prema[0]
this.labArray = this.prema[1]
this.finishCallBack = this.prema[2]
this.isPlayAnim = this.prema[3] || true
this.blackOpacity = this.prema[4] || 255
if(this.prema[5] === false){
this.hideSpineshouzhi = this.prema[5]
}else{
this.hideSpineshouzhi = true
}
if(!this.hideSpineshouzhi){
this.node.getChildByName('dianji').active = false
}
this.maskBlackNode.opacity = this.blackOpacity
this.bindNode()
if (this.nodeArray.length == 0) {
this.close()
//EventMgr.emitEvent_custom(ryw_Event.swallowToucheFinishEvent);
} else {
let nextNode = this.nodeArray.shift()
this.nextNode(nextNode)
}
}
}