MatchMaster/assets/seven_day_gift/SevenDayHitTest.ts

43 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import masks from "./SevenDayHitMasks";
/** 根据原图透明度判断可见 UI,不把贴图矩形内的空白当作弹窗。 */
export default class SevenDayHitTest {
// 从上层子节点往背景检查,透明处继续寻找下方的可见 UI。
public static findVisible(node: cc.Node, screenPoint: cc.Vec2): cc.Node {
// 装饰光芒不扩大卡片的可点击范围。
if (node.name === "catGlow") return null;
if (!node.activeInHierarchy || node.opacity === 0) return null;
for (let i = node.children.length - 1; i >= 0; i--) {
const hit = this.findVisible(node.children[i], screenPoint);
if (hit) return hit;
}
const sprite = node.getComponent(cc.Sprite);
const label = node.getComponent(cc.Label);
if ((!sprite || !sprite.enabled || !sprite.spriteFrame) && (!label || !label.enabled)) return null;
const camera = cc.Camera.findCamera(node);
const world = camera ? camera.getScreenToWorldPoint(screenPoint) : screenPoint;
const local = node.convertToNodeSpaceAR(cc.v2(world.x, world.y));
let u = local.x / node.width + node.anchorX;
let v = 1 - (local.y / node.height + node.anchorY);
if (!isFinite(u) || !isFinite(v) || u < 0 || u >= 1 || v < 0 || v >= 1) return null;
if (!sprite || !sprite.enabled || !sprite.spriteFrame) return node;
// SpriteFrame 的 UUID 不随动态图集打包而变化,命中数据无需读取 GPU。
const frame = sprite.spriteFrame;
const mask = masks[(frame as any)._uuid];
if (!mask || sprite.type !== cc.Sprite.Type.SIMPLE) return node;
if (!sprite.trim) {
const size = frame.getOriginalSize();
const offset = frame.getOffset();
u = (u * size.width - (size.width - mask.width) / 2 - offset.x) / mask.width;
v = (v * size.height - (size.height - mask.height) / 2 + offset.y) / mask.height;
}
if (u < 0 || u >= 1 || v < 0 || v >= 1) return null;
const x = Math.floor(u * mask.width);
const runs = mask.spans[mask.rows[Math.floor(v * mask.height)]];
for (let i = 0; i < runs.length; i += 2) {
if (x >= runs[i] && x < runs[i + 1]) return node;
}
return null;
}
}