| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- import { _decorator, Component, Node, Tween, tween, Vec3 } from 'cc';
- const { ccclass, property } = _decorator;
- /**
- * 通用弹出动画控制器
- * 负责管理UI面板的显示和隐藏动画
- */
- @ccclass('PopUPAni')
- export class PopUPAni extends Component {
-
- // Gray节点引用
- @property(Node) grayNode: Node = null;
-
- /**
- * 显示面板动画
- * 面板从小到大的缩放动画,从屏幕中央弹出
- */
- public showPanel(): Promise<void> {
- return new Promise((resolve) => {
- // 设置Gray节点为true
- if (this.grayNode) {
- this.grayNode.active = true;
- }
-
- // 设置初始状态:位置居中,缩小到0
- this.node.setPosition(0, 0, 0); // 先移动到屏幕正中间
- this.node.setScale(Vec3.ZERO); // 然后设置缩放为0
-
- // 缩放动画:从0放大到1
- tween(this.node)
- .to(0.3, { scale: new Vec3(1, 1, 1) }, {
- easing: 'backOut' // 使用回弹缓动效果
- })
- .call(() => {
- resolve();
- })
- .start();
- });
- }
-
- /**
- * 隐藏面板动画
- * 面板从大到小的缩放动画,然后回到原来的画面外右侧位置并恢复原来大小
- * 注意:不操作面板的active状态,面板始终保持active=true
- */
- public hidePanel(): Promise<void> {
- return new Promise((resolve) => {
- // 缩放动画:从1缩小到0
- tween(this.node)
- .to(0.2, { scale: Vec3.ZERO }, {
- easing: 'backIn' // 使用回弹缓动效果
- })
- .call(() => {
- // 设置Gray节点为false
- if (this.grayNode) {
- this.grayNode.active = false;
- }
-
- // 面板缩放到0后,回到原来的画面外右侧位置并恢复原来大小
- // 假设原来位置在画面外右侧,这里设置一个合理的右侧位置
- this.node.setPosition(1000, 0, 0); // 移动到画面外右侧
- this.node.setScale(Vec3.ONE); // 恢复原来大小
- // 不操作 this.node.active,保持面板原有的active状态
- resolve();
- })
- .start();
- });
- }
-
- /**
- * 立即隐藏面板(无动画)
- * 注意:不操作面板的active状态,面板始终保持active=true
- */
- public hidePanelImmediate(): void {
- // 设置Gray节点为false
- if (this.grayNode) {
- this.grayNode.active = false;
- }
-
- this.node.setScale(Vec3.ZERO);
- // 立即移动到画面外右侧位置并恢复原来大小
- this.node.setPosition(1000, 0, 0); // 移动到画面外右侧
- this.node.setScale(Vec3.ONE); // 恢复原来大小
- // 不操作 this.node.active,保持面板原有的active状态
- }
-
- /**
- * 立即显示面板(无动画)
- * 注意:不操作面板的active状态,面板始终保持active=true
- */
- public showPanelImmediate(): void {
- // 设置Gray节点为true
- if (this.grayNode) {
- this.grayNode.active = true;
- }
-
- this.node.setPosition(0, 0, 0); // 先移动到屏幕正中间
- this.node.setScale(Vec3.ONE); // 然后设置缩放为1
- // 不操作 this.node.active,保持面板原有的active状态
- }
-
- /**
- * 图标升级成功动画
- * 播放图标的放大缩小动画
- * @param iconNode 图标节点
- */
- public playIconUpgradeAnimation(iconNode: Node): Promise<void> {
- return new Promise((resolve) => {
- if (!iconNode) {
- resolve();
- return;
- }
-
- // 停止之前的动画,防止快速点击时动画冲突
- Tween.stopAllByTarget(iconNode);
-
- // 重置到原始缩放状态,确保动画从正确的状态开始
- iconNode.setScale(Vec3.ONE);
-
- // 保存原始缩放值
- const originalScale = Vec3.ONE.clone();
-
- // 创建缩放动画:放大到1.5倍再立即缩小回原始大小
- const scaleAnimation = tween(iconNode)
- .to(0.25, { scale: new Vec3(originalScale.x * 1.5, originalScale.y * 1.5, originalScale.z) }, {
- easing: 'sineOut'
- })
- .to(0.25, { scale: originalScale }, {
- easing: 'sineIn'
- });
-
- // 只播放缩放动画
- scaleAnimation.call(() => resolve()).start();
- });
- }
-
- /**
- * 提示图标动画
- * 播放缩小到0.7倍再放大到原来大小的重复动画,直到条件不满足为止
- * @param iconNode 图标节点
- * @param checkCondition 检查条件的回调函数,返回false时停止动画
- */
- public playIconTipAnimation(iconNode: Node, checkCondition?: () => boolean): void {
- if (!iconNode) return;
-
- // 停止之前的动画
- Tween.stopAllByTarget(iconNode);
-
- // 保存原始缩放值
- const originalScale = iconNode.scale.clone();
-
- // 如果没有提供检查条件,使用默认的无限重复动画
- if (!checkCondition) {
- const scaleAnimation = tween(iconNode)
- .to(0.5, { scale: new Vec3(originalScale.x * 0.7, originalScale.y * 0.7, originalScale.z) }, {
- easing: 'sineInOut'
- })
- .to(0.5, { scale: originalScale }, {
- easing: 'sineInOut'
- })
- .repeatForever(); // 无限重复
-
- scaleAnimation.start();
- return;
- }
-
- // 带条件检查的动画循环
- const playAnimationCycle = () => {
- // 在每次动画循环开始前检查条件
- if (!checkCondition()) {
- // 条件不满足,停止动画并恢复原始缩放
- this.stopIconTipAnimation(iconNode);
- return;
- }
-
- // 创建一次完整的缩放动画循环
- const scaleAnimation = tween(iconNode)
- .to(0.5, { scale: new Vec3(originalScale.x * 0.7, originalScale.y * 0.7, originalScale.z) }, {
- easing: 'sineInOut'
- })
- .to(0.5, { scale: originalScale }, {
- easing: 'sineInOut'
- })
- .call(() => {
- // 一次循环完成后,递归调用下一次循环
- playAnimationCycle();
- });
-
- scaleAnimation.start();
- };
-
- // 开始第一次动画循环
- playAnimationCycle();
- }
-
- /**
- * 停止提示图标动画
- * @param iconNode 图标节点
- */
- public stopIconTipAnimation(iconNode: Node): void {
- if (!iconNode) return;
-
- // 停止所有动画
- Tween.stopAllByTarget(iconNode);
-
- // 恢复原始缩放
- iconNode.setScale(Vec3.ONE);
- }
- }
|