82 lines
3.7 KiB
TypeScript
82 lines
3.7 KiB
TypeScript
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;
|
||
});
|
||
}
|
||
}
|