UITween.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import { Tween } from "cc";
  2. import { Component, Enum, EventHandler, Node, quat, Quat, tween, v3, Vec3, _decorator } from "cc";
  3. import { TweenEasing } from "./TweenEasing";
  4. const { ccclass, property } = _decorator;
  5. /**
  6. * 缓动数据
  7. * @author 袁浩
  8. */
  9. @ccclass("PropsData")
  10. export class PropsData {
  11. @property({ tooltip: "坐标", type: Vec3 })
  12. public position: Vec3 = new Vec3();
  13. @property({ tooltip: "旋转", type: Vec3 })
  14. public eulerAngles: Vec3 = new Vec3();
  15. @property({ tooltip: "缩放", type: Vec3 })
  16. public scale: Vec3 = new Vec3(1, 1, 1);
  17. }
  18. /**
  19. * 缓动数据
  20. * @author 袁浩
  21. */
  22. @ccclass("TweenData")
  23. export class TweenData {
  24. @property({ tooltip: "属性数据", type: PropsData })
  25. public propsData: PropsData;
  26. @property({ tooltip: "持续时间,单位为秒" })
  27. public duration: number = 0.3;
  28. @property({ tooltip: "延迟时间,单位为秒" })
  29. public delay: number = 0;
  30. @property({ tooltip: "是否为差值" })
  31. public isOffset: boolean = false;
  32. @property({ tooltip: "当缓动动作完成时触发", type: EventHandler })
  33. public onComplete: EventHandler;
  34. @property({ tooltip: "当缓动动作启动时触发", type: EventHandler })
  35. public onStart: EventHandler;
  36. @property({ tooltip: "当缓动动作更新时触发", type: EventHandler })
  37. public onUpdate: EventHandler;
  38. }
  39. /**
  40. * 缓动组件,目前只支持节点的三个基础属性
  41. * @author 袁浩
  42. */
  43. @ccclass('UITween')
  44. export class UITween extends Component {
  45. @property({ tooltip: "节点初始属性", type: PropsData })
  46. public fromData: PropsData;
  47. @property({ tooltip: "节点目标属性", type: [TweenData] })
  48. public targetData: TweenData[] = [];
  49. @property({ tooltip: "要播放缓动动画的目标,不填则是当前节点", type: Node })
  50. public target: Node;
  51. @property({ tooltip: "是否在缓动组件运行时自动播放缓动动画" })
  52. public playOnLoad: boolean = false;
  53. @property({ tooltip: "缓动效果", type: Enum(TweenEasing) })
  54. public tweenEasing: TweenEasing = TweenEasing.linear;
  55. @property({ tooltip: "执行次数,为0则一直重复执行" })
  56. public repeat: number = 1;
  57. @property({ tooltip: "单次缓动序列执行完毕时触", type: EventHandler })
  58. public onOneRepeatComplete: EventHandler;
  59. start() {
  60. !this.target && (this.target = this.node);
  61. this.target = this.target || this.node;
  62. this.currentRepeat = this.repeat;
  63. this.playOnLoad && this.play();
  64. }
  65. private t: Tween<any>;
  66. private currentRepeat: number;
  67. public play() {
  68. if (this.repeat == 0) {
  69. this.t = tween(this.target);
  70. this.readyPlay();
  71. this.t = this.t.call(this.play.bind(this));
  72. this.t.start();
  73. }
  74. else if (this.currentRepeat) {
  75. this.t = tween(this.target);
  76. this.readyPlay();
  77. this.t = this.t.call(this.play.bind(this));
  78. this.currentRepeat--;
  79. this.t.start();
  80. }
  81. else {
  82. this.t = null;
  83. this.currentRepeat = this.repeat;
  84. }
  85. }
  86. public readyPlay() {
  87. let self = this;
  88. if (this.fromData) {
  89. this.node.position = this.fromData.position.clone();
  90. this.node.scale = this.fromData.scale.clone();
  91. this.node.eulerAngles = this.fromData.eulerAngles.clone();
  92. }
  93. if (this.targetData.length) {
  94. for (let i = 0; i < this.targetData.length; i++) {
  95. const targetData = this.targetData[i];
  96. if (targetData.delay != 0) {
  97. this.t = this.t.delay(targetData.delay);
  98. }
  99. let toData = {
  100. position: targetData.propsData.position,
  101. scale: targetData.propsData.scale,
  102. eulerAngles: targetData.propsData.eulerAngles
  103. }
  104. if (targetData.isOffset) {
  105. toData.position = this.node.position.clone().add(targetData.propsData.position);
  106. toData.scale = this.node.scale.clone().add(targetData.propsData.scale);
  107. toData.eulerAngles = this.node.eulerAngles.clone().add(targetData.propsData.eulerAngles);
  108. }
  109. this.t = this.t.to(
  110. targetData.duration,
  111. toData,
  112. {
  113. easing: TweenEasing[this.tweenEasing] as any,
  114. onComplete: (target: Node) => {
  115. targetData.onComplete && targetData.onComplete.emit([target]);
  116. },
  117. onStart: (target: Node) => { targetData.onStart && targetData.onStart.emit([target]) },
  118. onUpdate: (target: Node, ratio: number) => { targetData.onUpdate && targetData.onUpdate.emit([target, ratio]) }
  119. }
  120. );
  121. }
  122. }
  123. if (this.onOneRepeatComplete) {
  124. this.t = this.t.call(() => {
  125. self.onOneRepeatComplete.emit([this, this.t])
  126. });
  127. }
  128. }
  129. }