ToastAni.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import { _decorator, Component, Node, UITransform, Label, tween, Vec3, find } from 'cc';
  2. import EventBus, { GameEvents } from '../Core/EventBus';
  3. const { ccclass, property } = _decorator;
  4. @ccclass('ToastAni')
  5. export class ToastAni extends Component {
  6. private originalPosition: Vec3 = new Vec3();
  7. private isAnimating: boolean = false;
  8. private currentDuration: number = 0; // 默认显示时长(秒)
  9. onLoad() {
  10. // 保存初始位置
  11. this.originalPosition = this.node.position.clone();
  12. // 监听Toast事件
  13. this.setupEventListeners();
  14. // 初始化位置到屏幕左边外侧
  15. this.resetToInitialPosition();
  16. }
  17. private setupEventListeners() {
  18. EventBus.getInstance().on(GameEvents.SHOW_TOAST, this.onShowToast, this);
  19. EventBus.getInstance().on(GameEvents.HIDE_TOAST, this.onHideToast, this);
  20. }
  21. private onShowToast(data: { message: string, duration?: number }) {
  22. if (this.isAnimating) {
  23. return;
  24. }
  25. // 设置Toast文本
  26. this.setToastMessage(data.message);
  27. // 播放滑入动画
  28. this.playSlideInAnimation();
  29. }
  30. private onHideToast() {
  31. if (!this.isAnimating) {
  32. this.playSlideOutAnimation();
  33. }
  34. }
  35. private setToastMessage(message: string) {
  36. const labelNode = this.node.getChildByName('label');
  37. if (labelNode) {
  38. const label = labelNode.getComponent(Label);
  39. if (label) {
  40. label.string = message;
  41. }
  42. }
  43. }
  44. private resetToInitialPosition() {
  45. // 重置到原始位置(屏幕外侧的起始位置)
  46. this.node.setPosition(this.originalPosition);
  47. }
  48. private playSlideInAnimation() {
  49. if (this.isAnimating) {
  50. return;
  51. }
  52. this.isAnimating = true;
  53. // 确保从起始位置开始
  54. this.resetToInitialPosition();
  55. // 滑入到屏幕中央位置显示
  56. const targetPosition = new Vec3(0, this.originalPosition.y, this.originalPosition.z);
  57. tween(this.node)
  58. .to(0.5, { position: targetPosition }, { easing: 'sineOut' })
  59. .delay(0.5)
  60. .call(() => {
  61. this.playSlideOutAnimation();
  62. })
  63. .start();
  64. }
  65. private playSlideOutAnimation() {
  66. if (!this.isAnimating) {
  67. return;
  68. }
  69. // 获取Canvas尺寸来计算屏幕边界
  70. const canvas = find('Canvas');
  71. if (canvas) {
  72. const canvasTransform = canvas.getComponent(UITransform);
  73. if (canvasTransform) {
  74. const canvasWidth = canvasTransform.contentSize.width;
  75. // 获取Toast节点的宽度
  76. const toastTransform = this.node.getComponent(UITransform);
  77. const toastWidth = toastTransform ? toastTransform.contentSize.width : 200;
  78. // 滑出到屏幕右边外侧消失
  79. const rightPosition = new Vec3(canvasWidth / 2 + toastWidth / 2 + 50, this.node.position.y, this.node.position.z);
  80. tween(this.node)
  81. .to(0.5, { position: rightPosition }, { easing: 'sineIn' })
  82. .call(() => {
  83. // 动画完成后立即重置到初始位置
  84. this.resetToInitialPosition();
  85. this.isAnimating = false;
  86. })
  87. .start();
  88. }
  89. }
  90. }
  91. onDestroy() {
  92. // 移除事件监听
  93. EventBus.getInstance().off(GameEvents.SHOW_TOAST, this.onShowToast, this);
  94. EventBus.getInstance().off(GameEvents.HIDE_TOAST, this.onHideToast, this);
  95. }
  96. }