MatchMaster/assets/Script/RainbowOldVisual.ts
2026-09-21 19:48:14 +08:00

82 lines
3.7 KiB
TypeScript
Raw Permalink 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 RainbowScroll from "./prop/RainbowScroll";
const { ccclass, property } = cc._decorator;
/** C 方案只覆盖底色,方块及其附件仍使用原节点。 */
@ccclass
export default class RainbowOldVisual extends cc.Component {
@property([cc.SpriteFrame])
shapeFrames: cc.SpriteFrame[] = [];
@property([cc.SpriteFrame])
maskFrames: cc.SpriteFrame[] = [];
apply(block: any): void {
const icon: cc.Node = block.node.getChildByName("icon");
const frame = this.shapeFrames[block.block_Info.block];
const maskFrame = this.maskFrames[block.block_Info.block];
const bg = this.node.getChildByName("bg");
const mask = this.node.getChildByName("mask");
this.node.setPosition(icon.position);
this.node.setAnchorPoint(icon.getAnchorPoint());
this.node.setContentSize(icon.getContentSize());
this.node.setScale(icon.scaleX, icon.scaleY);
this.node.angle = icon.angle;
this.node.setSiblingIndex(icon.getSiblingIndex());
const sprite = bg.getComponent(cc.Sprite);
sprite.sizeMode = cc.Sprite.SizeMode.CUSTOM;
sprite.trim = false;
sprite.spriteFrame = frame;
mask.getComponent(cc.Mask).spriteFrame = maskFrame;
this.alignFrame(bg, frame, icon);
// 共用 bg 的原画布布局,保留 mask 图片中的内收边距。
this.alignFrame(mask, frame, icon);
this.fitColors(mask);
const scroll = this.node.getComponent(RainbowScroll);
if (scroll) scroll.refreshGeometry();
icon.active = false;
}
/** Mask 按原画布绘制,Sprite 默认按裁剪矩形绘制,先还原透明边距。 */
private alignFrame(node: cc.Node, frame: cc.SpriteFrame, icon: cc.Node): void {
const rect = frame.getRect();
const original = frame.getOriginalSize();
const offset = frame.getOffset();
const sx = icon.width / rect.width;
const sy = icon.height / rect.height;
const left = -icon.anchorX * icon.width - (offset.x + (original.width - rect.width) / 2) * sx;
const bottom = -icon.anchorY * icon.height - (offset.y + (original.height - rect.height) / 2) * sy;
node.setAnchorPoint(0.5, 0.5);
node.setContentSize(original.width * sx, original.height * sy);
node.setPosition(left + node.width / 2, bottom + node.height / 2);
node.setScale(1, 1);
}
/** 两张镜像大纹理首尾相接;每一张都足以覆盖遮罩沿滚动轴的投影。 */
private fitColors(mask: cc.Node): void {
const colors = [mask.getChildByName("color1"), mask.getChildByName("color2")];
const radians = colors[0].angle * Math.PI / 180;
const cos = Math.cos(radians), sin = Math.sin(radians);
const direction = cc.v2(-sin, cos);
const width = Math.abs(mask.width * cos) + Math.abs(mask.height * sin) + 2;
const length = Math.abs(mask.width * sin) + Math.abs(mask.height * cos) + 2;
colors.forEach(color => {
const scale = Math.max(1, width / (color.width * Math.abs(color.scaleX)),
length / (color.height * Math.abs(color.scaleY)));
color.setScale(color.scaleX * scale, color.scaleY * scale);
});
let end = length / 2;
colors.forEach(color => {
const colorLength = color.height * Math.abs(color.scaleY);
const center = end - colorLength / 2;
const ox = (0.5 - color.anchorX) * color.width * color.scaleX;
const oy = (0.5 - color.anchorY) * color.height * color.scaleY;
color.setPosition(direction.x * center - (cos * ox - sin * oy),
direction.y * center - (sin * ox + cos * oy));
end -= colorLength;
});
}
}