const { ccclass, property } = cc._decorator; @ccclass export default class GuideHand extends cc.Component { @property(cc.Material) rippleMaterial: cc.Material = null; @property swingAngle: number = 8; @property ringWidth: number = 0.1; @property(cc.Vec2) tipPosition: cc.Vec2 = cc.v2(-58, 148); private baseAngle: number = 0; private elapsed: number = 0; private rippleDuration: number = 0; private ripple: cc.Node = null; private material: cc.Material = null; onLoad() { this.baseAngle = this.node.angle; const ripple = this.ripple = new cc.Node("handRipple"); ripple.active = false; ripple.parent = this.node.parent; // 光圈放在手的后面,独立于手旋转,点击位置保持不动。 ripple.setSiblingIndex(this.node.getSiblingIndex()); const sprite = ripple.addComponent(cc.Sprite); sprite.spriteFrame = this.node.getComponent(cc.Sprite).spriteFrame; sprite.sizeMode = cc.Sprite.SizeMode.CUSTOM; ripple.setContentSize(220, 220); sprite.setMaterial(0, this.rippleMaterial); this.material = sprite.getMaterial(0); this.material.setProperty("ringWidth", this.ringWidth); this.material.setProperty("center", [0.5, 0.5]); // 对齐 ripple_shrink:第三圈延后 0.6 秒,扩散到半径 0.475 时完全淡出。 this.rippleDuration = 0.6 + 0.475 / Number(this.material.getProperty("waveSpeed", 0)); } onEnable() { this.elapsed = 0; this.node.angle = this.baseAngle; this.ripple.active = false; this.material.setProperty("time", 0); } update(dt: number) { const pressDuration = 0.24; const releaseDuration = 0.32; const cycleDuration = pressDuration + this.rippleDuration; const previousTime = this.elapsed; this.elapsed = (this.elapsed + dt) % cycleDuration; if (this.elapsed < previousTime) this.ripple.active = false; const progress = this.elapsed < pressDuration ? this.elapsed / pressDuration : Math.max(0, 1 - (this.elapsed - pressDuration) / releaseDuration); this.node.angle = this.baseAngle + this.swingAngle * (1 - Math.cos(progress * Math.PI)) / 2; if (this.elapsed < pressDuration) { this.ripple.active = false; return; } if (!this.ripple.active) { // 按下瞬间的指尖坐标;松手时光圈不跟着移动。 const angle = this.node.angle; this.node.angle = this.baseAngle + this.swingAngle; const tip = this.node.convertToWorldSpaceAR(this.tipPosition); this.ripple.setPosition(this.node.parent.convertToNodeSpaceAR(tip)); this.node.angle = angle; this.ripple.active = true; } this.material.setProperty("time", this.elapsed - pressDuration); } onDisable() { this.node.angle = this.baseAngle; if (cc.isValid(this.ripple)) this.ripple.active = false; } onDestroy() { if (cc.isValid(this.ripple)) this.ripple.destroy(); } }