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; }); } }