103 lines
3.1 KiB
TypeScript
103 lines
3.1 KiB
TypeScript
import { _decorator, Node, Tween, UIOpacity, Vec3, tween } from 'cc';
|
|
import { BaseView } from './BaseView';
|
|
const { ccclass, property } = _decorator;
|
|
|
|
@ccclass('BaseModal')
|
|
export class BaseModal extends BaseView {
|
|
@property([Node])
|
|
protected animationNodes: Node[] = [];
|
|
|
|
@property(Node)
|
|
protected backdropNode: Node | null = null;
|
|
|
|
@property
|
|
protected openAnimationEnabled: boolean = true;
|
|
|
|
@property
|
|
protected openAnimationDuration: number = 0.36;
|
|
|
|
private readonly _originalScales: Map<Node, Vec3> = new Map();
|
|
|
|
onViewShow(): void {
|
|
this.playOpenAnimation();
|
|
}
|
|
|
|
onViewHide(): void {
|
|
this.stopOpenAnimation();
|
|
}
|
|
|
|
protected playOpenAnimation(): void {
|
|
if (!this.openAnimationEnabled) {
|
|
return;
|
|
}
|
|
|
|
this.playBackdropFadeIn();
|
|
|
|
const targets = this.getAnimationTargets();
|
|
targets.forEach((target, index) => {
|
|
this.playBounceIn(target, index * 0.035);
|
|
});
|
|
}
|
|
|
|
protected stopOpenAnimation(): void {
|
|
this.getAnimationTargets().forEach((target) => {
|
|
Tween.stopAllByTarget(target);
|
|
});
|
|
|
|
const opacity = this.backdropNode?.getComponent(UIOpacity);
|
|
if (opacity) {
|
|
Tween.stopAllByTarget(opacity);
|
|
}
|
|
}
|
|
|
|
private getAnimationTargets(): Node[] {
|
|
const configuredTargets = this.animationNodes.filter((node) => node?.isValid);
|
|
return configuredTargets.length > 0 ? configuredTargets : [this.node];
|
|
}
|
|
|
|
private getOriginalScale(target: Node): Vec3 {
|
|
const cachedScale = this._originalScales.get(target);
|
|
if (cachedScale) {
|
|
return cachedScale;
|
|
}
|
|
|
|
const originalScale = target.scale.clone();
|
|
this._originalScales.set(target, originalScale);
|
|
return originalScale;
|
|
}
|
|
|
|
private playBounceIn(target: Node, delay: number): void {
|
|
const originalScale = this.getOriginalScale(target);
|
|
const startScale = this.multiplyScale(originalScale, 0.82);
|
|
const peakScale = this.multiplyScale(originalScale, 1.045);
|
|
|
|
Tween.stopAllByTarget(target);
|
|
target.setScale(startScale);
|
|
|
|
tween(target)
|
|
.delay(delay)
|
|
.to(this.openAnimationDuration * 0.58, { scale: peakScale }, { easing: 'backOut' })
|
|
.to(this.openAnimationDuration * 0.24, { scale: this.multiplyScale(originalScale, 0.985) }, { easing: 'sineOut' })
|
|
.to(this.openAnimationDuration * 0.18, { scale: originalScale }, { easing: 'sineOut' })
|
|
.start();
|
|
}
|
|
|
|
private playBackdropFadeIn(): void {
|
|
if (!this.backdropNode?.isValid) {
|
|
return;
|
|
}
|
|
|
|
const opacity = this.backdropNode.getComponent(UIOpacity) ?? this.backdropNode.addComponent(UIOpacity);
|
|
Tween.stopAllByTarget(opacity);
|
|
opacity.opacity = 0;
|
|
|
|
tween(opacity)
|
|
.to(0.18, { opacity: 255 }, { easing: 'sineOut' })
|
|
.start();
|
|
}
|
|
|
|
private multiplyScale(scale: Vec3, factor: number): Vec3 {
|
|
return new Vec3(scale.x * factor, scale.y * factor, scale.z);
|
|
}
|
|
}
|