const { ccclass, property } = cc._decorator; /** 两张镜像彩虹沿旋转后的纵轴循环,完全离开遮罩后接到另一张后面。 */ @ccclass export default class RainbowScroll extends cc.Component { @property(cc.Node) color1: cc.Node = null; @property(cc.Node) color2: cc.Node = null; @property({ tooltip: "彩虹向左上滚动的速度(每秒像素)", min: 0 }) speed: number = 60; private colors: cc.Node[] = []; private direction = cc.v2(0, 0); private exits: number[] = []; private loopLength = 0; onLoad(): void { // 预制体重存后引用可能为空,按既有节点层级恢复。 const mask = this.node.getChildByName("mask"); this.color1 = this.color1 || mask.getChildByName("color1"); this.color2 = this.color2 || mask.getChildByName("color2"); this.colors = [this.color1, this.color2]; const radians = this.color1.angle * Math.PI / 180; this.direction = cc.v2(-Math.sin(radians), Math.cos(radians)); const centers = this.colors.map(node => mask.convertToNodeSpaceAR(node.convertToWorldSpaceAR( cc.v2((0.5 - node.anchorX) * node.width, (0.5 - node.anchorY) * node.height)))); const offsets = centers.map((center, i) => cc.v2(center.x - this.colors[i].x, center.y - this.colors[i].y)); const lengths = this.colors.map(node => node.height * Math.abs(node.scaleY)); this.loopLength = lengths[0] + lengths[1]; const left = -mask.width * mask.anchorX; const bottom = -mask.height * mask.anchorY; const maskEnd = Math.max(left * this.direction.x, (left + mask.width) * this.direction.x) + Math.max(bottom * this.direction.y, (bottom + mask.height) * this.direction.y); this.exits = offsets.map((offset, i) => maskEnd + lengths[i] / 2 - offset.x * this.direction.x - offset.y * this.direction.y); } update(dt: number): void { const distance = (this.speed * dt) % this.loopLength; this.colors.forEach((node, i) => { node.x += this.direction.x * distance; node.y += this.direction.y * distance; if (node.x * this.direction.x + node.y * this.direction.y > this.exits[i]) { node.x -= this.direction.x * this.loopLength; node.y -= this.direction.y * this.loopLength; } }); } }