86 lines
3.1 KiB
TypeScript
86 lines
3.1 KiB
TypeScript
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();
|
||
}
|
||
}
|