ToastAni.ts 3.7 KB

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