Files
mp-xieyingeng/assets/scripts/core/BaseModal.ts
2026-04-26 16:20:37 +08:00

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);
}
}