|
@@ -1,4 +1,4 @@
|
|
|
-import { _decorator, Component, Node, Label, Sprite, Button, resources, SpriteFrame } from 'cc';
|
|
|
+import { _decorator, Component, Node, Label, Sprite, Button, resources, SpriteFrame, tween, Vec3, UIOpacity, UITransform, Color } from 'cc';
|
|
|
const { ccclass, property } = _decorator;
|
|
|
|
|
|
/**
|
|
@@ -56,13 +56,47 @@ export class PassCardManager extends Component {
|
|
|
})
|
|
|
closeButton: Button = null;
|
|
|
|
|
|
+ @property({
|
|
|
+ tooltip: '通行证面板动画时长(秒)',
|
|
|
+ range: [0.1, 2.0, 0.1]
|
|
|
+ })
|
|
|
+ animDuration: number = 0.5;
|
|
|
+
|
|
|
+ @property({
|
|
|
+ type: Node,
|
|
|
+ tooltip: '卡片阴影节点(可选)'
|
|
|
+ })
|
|
|
+ cardShadow: Node = null;
|
|
|
+
|
|
|
// 当前通行证数据
|
|
|
private currentPassData: PassCardData = null;
|
|
|
|
|
|
+ // 用于动画控制的UIOpacity组件
|
|
|
+ private passCardOpacity: UIOpacity = null;
|
|
|
+ private shadowOpacity: UIOpacity = null;
|
|
|
+
|
|
|
start() {
|
|
|
// 初始隐藏通行证面板
|
|
|
if (this.passCardPanel) {
|
|
|
this.passCardPanel.active = false;
|
|
|
+
|
|
|
+ // 确保面板有UIOpacity组件
|
|
|
+ this.passCardOpacity = this.passCardPanel.getComponent(UIOpacity);
|
|
|
+ if (!this.passCardOpacity) {
|
|
|
+ this.passCardOpacity = this.passCardPanel.addComponent(UIOpacity);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果有阴影节点,初始化它
|
|
|
+ if (this.cardShadow) {
|
|
|
+ this.shadowOpacity = this.cardShadow.getComponent(UIOpacity);
|
|
|
+ if (!this.shadowOpacity) {
|
|
|
+ this.shadowOpacity = this.cardShadow.addComponent(UIOpacity);
|
|
|
+ }
|
|
|
+ this.cardShadow.active = false;
|
|
|
+ } else {
|
|
|
+ // 自动创建阴影节点
|
|
|
+ this.createShadowNode();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 注册关闭按钮点击事件
|
|
@@ -77,6 +111,35 @@ export class PassCardManager extends Component {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 创建卡片阴影节点
|
|
|
+ */
|
|
|
+ private createShadowNode(): void {
|
|
|
+ if (!this.passCardPanel || this.cardShadow) return;
|
|
|
+
|
|
|
+ // 创建阴影节点
|
|
|
+ this.cardShadow = new Node('CardShadow');
|
|
|
+ this.passCardPanel.parent.insertChild(this.cardShadow, this.passCardPanel.getSiblingIndex());
|
|
|
+
|
|
|
+ // 设置阴影大小
|
|
|
+ const cardTransform = this.passCardPanel.getComponent(UITransform);
|
|
|
+ if (cardTransform) {
|
|
|
+ const shadowTransform = this.cardShadow.addComponent(UITransform);
|
|
|
+ shadowTransform.width = cardTransform.width * 0.9;
|
|
|
+ shadowTransform.height = cardTransform.height * 0.9;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加阴影图像
|
|
|
+ const shadowSprite = this.cardShadow.addComponent(Sprite);
|
|
|
+ shadowSprite.color = new Color(0, 0, 0, 180);
|
|
|
+
|
|
|
+ // 添加透明度控制
|
|
|
+ this.shadowOpacity = this.cardShadow.addComponent(UIOpacity);
|
|
|
+ this.shadowOpacity.opacity = 0;
|
|
|
+
|
|
|
+ this.cardShadow.active = false;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 关闭按钮点击事件处理
|
|
|
*/
|
|
@@ -103,9 +166,129 @@ export class PassCardManager extends Component {
|
|
|
// 更新UI显示
|
|
|
this.updatePassCardUI();
|
|
|
|
|
|
- // 显示面板
|
|
|
+ // 显示面板并播放动画
|
|
|
this.passCardPanel.active = true;
|
|
|
+ this.playShowAnimation();
|
|
|
console.log('通行证面板已显示');
|
|
|
+
|
|
|
+ // 确保阴影也显示
|
|
|
+ if (this.cardShadow) {
|
|
|
+ this.cardShadow.active = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 播放显示动画
|
|
|
+ */
|
|
|
+ private playShowAnimation(): void {
|
|
|
+ // 重置面板的初始状态
|
|
|
+ this.passCardPanel.setScale(new Vec3(0.6, 0.6, 1));
|
|
|
+ this.passCardPanel.setPosition(new Vec3(200, -100, 0)); // 从更远的地方传递过来
|
|
|
+ this.passCardPanel.setRotationFromEuler(new Vec3(0, 0, -15)); // 初始旋转角度
|
|
|
+
|
|
|
+ // 设置初始透明度
|
|
|
+ if (this.passCardOpacity) {
|
|
|
+ this.passCardOpacity.opacity = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置阴影初始状态
|
|
|
+ if (this.cardShadow && this.shadowOpacity) {
|
|
|
+ this.cardShadow.setPosition(new Vec3(210, -105, 0)); // 稍微偏移
|
|
|
+ this.cardShadow.setScale(new Vec3(0.6, 0.6, 1));
|
|
|
+ this.cardShadow.setRotationFromEuler(new Vec3(0, 0, -15));
|
|
|
+ this.shadowOpacity.opacity = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建动画序列 - 模拟传递过来的感觉
|
|
|
+ tween(this.passCardPanel)
|
|
|
+ // 第一阶段:接近动作,带有轻微旋转
|
|
|
+ .to(this.animDuration * 0.7, {
|
|
|
+ scale: new Vec3(1.05, 1.05, 1),
|
|
|
+ position: new Vec3(10, 5, 0),
|
|
|
+ eulerAngles: new Vec3(0, 0, 5) // 轻微旋转到反方向
|
|
|
+ }, {
|
|
|
+ easing: 'quartOut'
|
|
|
+ })
|
|
|
+ // 第二阶段:最终位置,带有轻微的回弹效果
|
|
|
+ .to(this.animDuration * 0.3, {
|
|
|
+ scale: new Vec3(1, 1, 1),
|
|
|
+ position: new Vec3(0, 0, 0),
|
|
|
+ eulerAngles: new Vec3(0, 0, 0)
|
|
|
+ }, {
|
|
|
+ easing: 'backOut'
|
|
|
+ })
|
|
|
+ // 第三阶段:添加轻微的抖动效果,模拟卡片放在桌面上的感觉
|
|
|
+ .call(() => {
|
|
|
+ this.addShakeEffect();
|
|
|
+ })
|
|
|
+ .start();
|
|
|
+
|
|
|
+ // 为阴影创建跟随动画
|
|
|
+ if (this.cardShadow) {
|
|
|
+ tween(this.cardShadow)
|
|
|
+ // 第一阶段
|
|
|
+ .to(this.animDuration * 0.7, {
|
|
|
+ scale: new Vec3(1.05, 1.05, 1),
|
|
|
+ position: new Vec3(15, 2, 0), // 稍微偏移以产生阴影效果
|
|
|
+ eulerAngles: new Vec3(0, 0, 5)
|
|
|
+ }, {
|
|
|
+ easing: 'quartOut'
|
|
|
+ })
|
|
|
+ // 第二阶段
|
|
|
+ .to(this.animDuration * 0.3, {
|
|
|
+ scale: new Vec3(1, 1, 1),
|
|
|
+ position: new Vec3(5, -3, 0), // 保持偏移
|
|
|
+ eulerAngles: new Vec3(0, 0, 0)
|
|
|
+ }, {
|
|
|
+ easing: 'backOut'
|
|
|
+ })
|
|
|
+ .start();
|
|
|
+
|
|
|
+ // 阴影透明度动画
|
|
|
+ if (this.shadowOpacity) {
|
|
|
+ tween(this.shadowOpacity)
|
|
|
+ .delay(this.animDuration * 0.2)
|
|
|
+ .to(this.animDuration * 0.5, { opacity: 100 }) // 半透明阴影
|
|
|
+ .start();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 单独为透明度创建动画
|
|
|
+ if (this.passCardOpacity) {
|
|
|
+ tween(this.passCardOpacity)
|
|
|
+ .to(this.animDuration * 0.5, { opacity: 255 })
|
|
|
+ .start();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加轻微的抖动效果
|
|
|
+ */
|
|
|
+ private addShakeEffect(): void {
|
|
|
+ // 创建一个轻微的抖动效果,模拟卡片被放置的震感
|
|
|
+ const originalPos = new Vec3(0, 0, 0);
|
|
|
+ const shakeAmount = 1.5; // 抖动幅度
|
|
|
+
|
|
|
+ tween(this.passCardPanel)
|
|
|
+ .to(0.05, { position: new Vec3(shakeAmount, 0, 0) })
|
|
|
+ .to(0.05, { position: new Vec3(-shakeAmount, 0, 0) })
|
|
|
+ .to(0.05, { position: new Vec3(shakeAmount * 0.5, 0, 0) })
|
|
|
+ .to(0.05, { position: new Vec3(-shakeAmount * 0.5, 0, 0) })
|
|
|
+ .to(0.05, { position: originalPos })
|
|
|
+ .start();
|
|
|
+
|
|
|
+ // 同时给阴影添加抖动效果
|
|
|
+ if (this.cardShadow) {
|
|
|
+ const shadowOriginalPos = new Vec3(5, -3, 0); // 阴影的原始位置
|
|
|
+
|
|
|
+ tween(this.cardShadow)
|
|
|
+ .to(0.05, { position: new Vec3(shadowOriginalPos.x + shakeAmount, shadowOriginalPos.y, 0) })
|
|
|
+ .to(0.05, { position: new Vec3(shadowOriginalPos.x - shakeAmount, shadowOriginalPos.y, 0) })
|
|
|
+ .to(0.05, { position: new Vec3(shadowOriginalPos.x + shakeAmount * 0.5, shadowOriginalPos.y, 0) })
|
|
|
+ .to(0.05, { position: new Vec3(shadowOriginalPos.x - shakeAmount * 0.5, shadowOriginalPos.y, 0) })
|
|
|
+ .to(0.05, { position: shadowOriginalPos })
|
|
|
+ .start();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -115,13 +298,85 @@ export class PassCardManager extends Component {
|
|
|
console.log('hidePassCard 被调用');
|
|
|
|
|
|
if (this.passCardPanel) {
|
|
|
- this.passCardPanel.active = false;
|
|
|
- console.log('通行证面板已隐藏');
|
|
|
+ // 播放隐藏动画
|
|
|
+ this.playHideAnimation(() => {
|
|
|
+ this.passCardPanel.active = false;
|
|
|
+ console.log('通行证面板已隐藏');
|
|
|
+ });
|
|
|
} else {
|
|
|
console.error('通行证面板未设置,无法隐藏');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 播放隐藏动画
|
|
|
+ * @param callback 动画完成回调
|
|
|
+ */
|
|
|
+ private playHideAnimation(callback?: Function): void {
|
|
|
+ // 创建移动和缩放动画 - 模拟被人收回的感觉
|
|
|
+ tween(this.passCardPanel)
|
|
|
+ // 首先上抬一点,像是被拿起
|
|
|
+ .to(this.animDuration * 0.2, {
|
|
|
+ position: new Vec3(0, 10, 0),
|
|
|
+ eulerAngles: new Vec3(0, 0, -5)
|
|
|
+ }, {
|
|
|
+ easing: 'sineOut'
|
|
|
+ })
|
|
|
+ // 然后向远处移动,同时旋转
|
|
|
+ .to(this.animDuration * 0.6, {
|
|
|
+ scale: new Vec3(0.7, 0.7, 1),
|
|
|
+ position: new Vec3(-180, 50, 0),
|
|
|
+ eulerAngles: new Vec3(0, 0, -15)
|
|
|
+ }, {
|
|
|
+ easing: 'quartIn'
|
|
|
+ })
|
|
|
+ .call(() => {
|
|
|
+ if (callback) callback();
|
|
|
+ })
|
|
|
+ .start();
|
|
|
+
|
|
|
+ // 阴影的隐藏动画
|
|
|
+ if (this.cardShadow) {
|
|
|
+ tween(this.cardShadow)
|
|
|
+ // 首先上抬一点,跟随卡片
|
|
|
+ .to(this.animDuration * 0.2, {
|
|
|
+ position: new Vec3(5, 7, 0), // 保持偏移
|
|
|
+ eulerAngles: new Vec3(0, 0, -5)
|
|
|
+ }, {
|
|
|
+ easing: 'sineOut'
|
|
|
+ })
|
|
|
+ // 然后向远处移动
|
|
|
+ .to(this.animDuration * 0.6, {
|
|
|
+ scale: new Vec3(0.7, 0.7, 1),
|
|
|
+ position: new Vec3(-175, 47, 0), // 保持偏移
|
|
|
+ eulerAngles: new Vec3(0, 0, -15)
|
|
|
+ }, {
|
|
|
+ easing: 'quartIn'
|
|
|
+ })
|
|
|
+ .call(() => {
|
|
|
+ if (this.cardShadow) {
|
|
|
+ this.cardShadow.active = false;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .start();
|
|
|
+
|
|
|
+ // 阴影透明度动画
|
|
|
+ if (this.shadowOpacity) {
|
|
|
+ tween(this.shadowOpacity)
|
|
|
+ .to(this.animDuration * 0.5, { opacity: 0 })
|
|
|
+ .start();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 单独为透明度创建动画,稍微延迟开始
|
|
|
+ if (this.passCardOpacity) {
|
|
|
+ tween(this.passCardOpacity)
|
|
|
+ .delay(this.animDuration * 0.1)
|
|
|
+ .to(this.animDuration * 0.7, { opacity: 0 })
|
|
|
+ .start();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 更新通行证UI
|
|
|
*/
|