RewardFly.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import { Component, EventTouch, Node, Prefab, UIOpacity, UITransform, Vec3, Widget, _decorator, easing, instantiate, tween, v3 } from 'cc';
  2. const { ccclass, requireComponent } = _decorator;
  3. @ccclass('RewardFly')
  4. @requireComponent(UITransform)
  5. export class RewardFly extends Component {
  6. protected onLoad() {
  7. //this.node.on(Node.EventType.TOUCH_START, function (event: EventTouch) {
  8. //event.propagationStopped = true;
  9. //event.preventSwallow = true;
  10. //}, this, true);
  11. }
  12. protected onDisable() {
  13. this.node.destroyAllChildren();
  14. }
  15. private convertToNodeSpaceAR(target: Node | Vec3) {
  16. if (target instanceof Node) {
  17. return this.node.getComponent(UITransform).convertToNodeSpaceAR(target.getComponent(UITransform).convertToWorldSpaceAR(Vec3.ZERO));
  18. }
  19. return this.node.getComponent(UITransform).convertToNodeSpaceAR(target);
  20. }
  21. public add(opts: {
  22. /**物品 */
  23. item: Prefab | Node,
  24. /**物品数量 */
  25. count: number,
  26. /**起始位置(节点或世界坐标) */
  27. start: Node | Vec3,
  28. /**终点位置(节点或世界坐标) */
  29. end: Node | Vec3,
  30. /**起点炸开的范围[x, y], 默认[100, 100] */
  31. startRange?: [number, number],
  32. /**终点偏移的范围[x, y], 默认[0, 0] */
  33. endOffset?: [number, number],
  34. /**开始接触 */
  35. onBegin?: (nodeCopy: Node | null) => any,
  36. /**持续接触(包括开始) */
  37. onContact?: (nodeCopy: Node | null) => any,
  38. /**动画结束 */
  39. onFinish?: (nodeCopy: Node | null) => any
  40. /**拷贝highlightArea或end至当前节点下, 优先highlightArea */
  41. highlight?: boolean,
  42. /**高亮区域,依赖highlight开启 */
  43. highlightArea?: Node,
  44. /**高亮位置偏移[x, y],依赖highlight开启, 默认[0, 0] */
  45. highlightOffset?: [number, number],
  46. }) {
  47. const startPos = this.convertToNodeSpaceAR(opts.start);
  48. const endPos = this.convertToNodeSpaceAR(opts.end);
  49. if (opts.endOffset) {
  50. endPos.add3f(opts.endOffset[0], opts.endOffset[1], 0);
  51. }
  52. let nodeCopy: Node = null;
  53. if (opts.highlight) {
  54. if (opts.highlightOffset) {
  55. endPos.add3f(opts.highlightOffset[0], opts.highlightOffset[1], 0);
  56. }
  57. if (opts.highlightArea) {
  58. const endAreaPos = this.convertToNodeSpaceAR(opts.highlightArea);
  59. if (opts.highlightOffset) {
  60. endAreaPos.add3f(opts.highlightOffset[0], opts.highlightOffset[1], 0);
  61. }
  62. nodeCopy = instantiate(opts.highlightArea);
  63. nodeCopy.getComponent(Widget)?.destroy();
  64. nodeCopy.setParent(this.node);
  65. nodeCopy.setPosition(endAreaPos);
  66. } else if (Node.isNode(opts.end)) {
  67. nodeCopy = instantiate(opts.end);
  68. nodeCopy.getComponent(Widget)?.destroy();
  69. nodeCopy.setParent(this.node);
  70. nodeCopy.setPosition(endPos);
  71. }
  72. }
  73. for (let index = 0; index < opts.count; index++) {
  74. const aniNode = instantiate(opts.item) as Node;
  75. aniNode.setPosition(startPos);
  76. aniNode.setParent(this.node);
  77. // 炸开位置
  78. const midPos = v3(startPos.x, startPos.y, 0);
  79. midPos.x += (Math.random() * 2 - 1) * (opts.startRange ? opts.startRange[0] : 100);
  80. midPos.y += (Math.random() * 2 - 1) * (opts.startRange ? opts.startRange[1] : 100);
  81. // 执行动画
  82. (aniNode.getComponent(UIOpacity) || aniNode.addComponent(UIOpacity)).opacity = 0;
  83. tween(aniNode)
  84. .delay(index * 0.025)
  85. .call(() => {
  86. aniNode.getComponent(UIOpacity).opacity = 200;
  87. tween(aniNode.getComponent(UIOpacity))
  88. .to(0.4, { opacity: 255 }, { easing: easing.expoOut })
  89. .start();
  90. })
  91. .to(0.4, { position: midPos }, { easing: easing.expoOut })
  92. .call(() => {
  93. tween(aniNode.getComponent(UIOpacity))
  94. .delay(0.5)
  95. .to(0.1, { opacity: 70 })
  96. .start();
  97. })
  98. .to(0.6, { position: endPos }, { easing: easing.expoIn })
  99. .call(() => {
  100. if (index === 0) {
  101. // 结束节点缩放
  102. if (nodeCopy) {
  103. const scale = v3(nodeCopy.scale);
  104. tween(nodeCopy)
  105. .to(0.1, { scale: v3(scale.x * 1.3, scale.y * 1.3) })
  106. .delay(0.025 * Math.max(opts.count, 4))
  107. .to(0.1, { scale: scale })
  108. .call(() => {
  109. // 结束节点透明销毁
  110. const uiOpacity = nodeCopy.getComponent(UIOpacity) || nodeCopy.addComponent(UIOpacity);
  111. tween(uiOpacity)
  112. .to(0.1, { opacity: uiOpacity.opacity * 0.3 })
  113. .call(() => nodeCopy.destroy())
  114. .start();
  115. })
  116. .start();
  117. }
  118. opts.onBegin && opts.onBegin(nodeCopy);
  119. }
  120. opts.onContact && opts.onContact(nodeCopy);
  121. })
  122. .delay(0.01)
  123. .call(() => {
  124. aniNode.destroy();
  125. if (index === opts.count - 1) {
  126. opts.onFinish && opts.onFinish(nodeCopy);
  127. }
  128. }).start();
  129. }
  130. }
  131. }