UITween.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. import { TweenEasing } from "./TweenEasing";
  2. const { ccclass, property, executeInEditMode, playOnFocus } = cc._decorator;
  3. /**
  4. * 缓动数据
  5. * @author 薛鸿潇
  6. */
  7. enum ActionType{
  8. Act_Absolute,
  9. Act_relative,
  10. }
  11. @ccclass("PropsData")
  12. export class PropsData {
  13. @property({ displayName: "坐标" })
  14. public position: cc.Vec2 = cc.Vec2.ZERO;
  15. @property({ displayName: "旋转" })
  16. public angle: number = 0;
  17. @property({ displayName: "缩放" })
  18. public scale: number = 1;
  19. @property({displayName: "显示隐藏", tooltip: '打勾是显示'})
  20. public active: boolean = true;
  21. }
  22. /**
  23. * 缓动数据
  24. * @author 薛鸿潇
  25. */
  26. @ccclass("TweenData")
  27. export class TweenData {
  28. @property({ displayName: "属性数据", type: PropsData })
  29. public propsData: PropsData = new PropsData();
  30. @property({ displayName: "持续时间", tooltip: '单位:秒' })
  31. public duration: number = 0.3;
  32. @property({ displayName: "延迟时间", tooltip: '单位:秒' })
  33. public delay: number = 0;
  34. @property({ displayName: "是否为差值" })
  35. public isOffset: boolean = false;
  36. @property({ displayName: '完成回调', tooltip: "缓动完成时触发", type: cc.Component.EventHandler })
  37. public onComplete: cc.Component.EventHandler[] = [];
  38. @property({ displayName: '开始回调', tooltip: "缓动启动时触发", type: cc.Component.EventHandler })
  39. public onStart: cc.Component.EventHandler[] = [];
  40. @property({ displayName: '过程回调', tooltip: "缓动更新时触发", type: cc.Component.EventHandler })
  41. public onUpdate: cc.Component.EventHandler[] = [];
  42. }
  43. /**
  44. * 缓动组件,目前只支持节点的三个基础属性
  45. * @author 薛鸿潇
  46. */
  47. @ccclass
  48. @executeInEditMode()
  49. @playOnFocus()
  50. export class UITween extends cc.Component {
  51. @property({ displayName: "节点初始属性", type: PropsData })
  52. public fromData: PropsData = new PropsData();
  53. @property({ displayName: "节点目标属性", type: TweenData })
  54. public targetData: TweenData[] = [];
  55. @property({ displayName: '缓动节点', tooltip: "要播放缓动动画的目标,不填则是当前节点", type: cc.Node })
  56. public target: cc.Node = null;
  57. @property({ displayName: "缓动效果", type: cc.Enum(TweenEasing) })
  58. public tweenEasing: TweenEasing = TweenEasing.sineInOut;
  59. @property({ displayName: '执行次数', tooltip: "为0则一直重复执行" })
  60. public repeat: number = 1;
  61. @property({ displayName: "单次完成回调", tooltip: '单次缓动序列执行完毕时触发', type: cc.Component.EventHandler })
  62. public onOneRepeatComplete: cc.Component.EventHandler = new cc.Component.EventHandler();
  63. @property({ displayName: "自动播放" })
  64. public playOnLoad: boolean = true;
  65. @property({displayName: "绝对移动or相对移动", type: cc.Enum(ActionType)})
  66. public actType: ActionType = ActionType.Act_Absolute;
  67. @property({displayName:'是否设置起始位置为屏幕旁边按屏幕加节点尺寸的一半'})
  68. public isSetSuitStartPos: boolean = false;
  69. @property({displayName: '是否延时设置初始属性'})
  70. public isDelaySetOrigin = null;
  71. private _edit_play: boolean = false;
  72. @property({ displayName: "编辑器预览" })
  73. get edit_play(): boolean {
  74. if (this._edit_play && !this.edit_playing) {
  75. this.edit_playing = true;
  76. this.play();
  77. }
  78. return this._edit_play;
  79. }
  80. set edit_play(v: boolean) {
  81. this._edit_play = v;
  82. if (this.target && v) {
  83. cc.Tween.stopAllByTarget(this.target);
  84. }
  85. if (!v) this.edit_playing = false;
  86. }
  87. private resetProperty: boolean = false;
  88. @property({displayName: '重置基础属性'})
  89. get reset_property():boolean{
  90. if(this.resetProperty)
  91. {
  92. this.fromData.position = cc.v2(this.node.position.x, this.node.position.y);
  93. this.fromData.angle = this.node.angle;
  94. this.fromData.scale = this.node.scale;
  95. for(let i = 0; i != this.targetData.length; ++i)
  96. {
  97. let target = this.targetData[i];
  98. target.propsData.position = cc.v2(this.node.position.x, this.node.position.y);
  99. target.propsData.angle = this.node.angle;
  100. target.propsData.scale = this.node.scale;
  101. }
  102. this.resetProperty = false;
  103. }
  104. return this.resetProperty;
  105. }
  106. set reset_property(v){
  107. this.resetProperty = v;
  108. }
  109. /** 编辑器是否正在播放 */
  110. private edit_playing = false;
  111. public start() {
  112. !this.target && (this.target = this.node);
  113. this.target = this.target || this.node;
  114. this.currentRepeat = this.repeat;
  115. if (CC_EDITOR) {
  116. this._edit_play && this.play();
  117. } else {
  118. this.playOnLoad && this.play();
  119. }
  120. }
  121. private t: cc.Tween<any>;
  122. /** 剩余播放次数 */
  123. private currentRepeat: number;
  124. public play() {
  125. if (CC_EDITOR && !this.edit_playing) return;
  126. if (this.repeat == 0) {
  127. this.t = cc.tween(this.target);
  128. this.readyPlay();
  129. this.t = this.t.call(this.play.bind(this));
  130. this.t.start();
  131. }
  132. else if (this.currentRepeat) {
  133. this.t = cc.tween(this.target);
  134. this.readyPlay();
  135. this.t = this.t.call(this.play.bind(this));
  136. this.currentRepeat--;
  137. this.t.start();
  138. }
  139. else {
  140. this.t = null;
  141. this.currentRepeat = this.repeat;
  142. this.edit_play = false;
  143. }
  144. }
  145. public readyPlay() {
  146. let self = this;
  147. if (this.fromData) {
  148. if(this.isSetSuitStartPos)
  149. {
  150. if(this.fromData.position.x >0)
  151. {
  152. this.fromData.position.x = cc.winSize.width / 2 + this.target.getContentSize().width/2;
  153. }else{
  154. this.fromData.position.x = -cc.winSize.width / 2 - this.target.getContentSize().width/2;
  155. }
  156. }
  157. this.node.setPosition(this.fromData.position.clone());
  158. this.node.scale = this.fromData.scale;
  159. this.node.angle = this.fromData.angle;
  160. this.node.active = this.fromData.active;
  161. }
  162. if (this.targetData.length) {
  163. for (let i = 0; i < this.targetData.length; i++) {
  164. const targetData = this.targetData[i];
  165. if (targetData.delay != 0) {
  166. this.t = this.t.delay(targetData.delay);
  167. }
  168. if(targetData.propsData.active)
  169. {
  170. this.t = this.t.call(()=>{
  171. this.node.active = true;
  172. });
  173. }else{
  174. this.t = this.t.call(()=>{
  175. this.node.active = false;
  176. });
  177. }
  178. let toData = {
  179. position: targetData.propsData.position,
  180. scale: targetData.propsData.scale,
  181. angle: targetData.propsData.angle,
  182. }
  183. if (targetData.isOffset) {
  184. toData.position = this.node.getPosition().add(targetData.propsData.position);
  185. toData.scale = this.node.scale + targetData.propsData.scale;
  186. toData.angle = this.node.angle + targetData.propsData.angle;
  187. }
  188. if(this.actType == ActionType.Act_Absolute)
  189. {
  190. this.t = this.t.to(
  191. targetData.duration,
  192. toData,
  193. {
  194. easing: TweenEasing[this.tweenEasing] as any,
  195. onComplete: (target: cc.Node) => {
  196. console.log("----------tweenComplete");
  197. if(targetData.onComplete && targetData.onComplete.length > 0)
  198. {
  199. for(let i = 0; i != targetData.onComplete.length; ++i)
  200. {
  201. targetData.onComplete[i].emit([target]);
  202. }
  203. }
  204. //targetData.onComplete && targetData.onComplete.emit([target]);
  205. // this.edit_playing = false;
  206. // this._edit_play = false;
  207. },
  208. onStart: (target: cc.Node) => {
  209. console.log("----------tweenStart");
  210. //targetData.onStart && targetData.onStart.emit([target])
  211. if(targetData.onStart && targetData.onStart.length > 0)
  212. {
  213. for(let i = 0; i != targetData.onStart.length; ++i)
  214. {
  215. targetData.onStart[i].emit([target]);
  216. }
  217. }
  218. },
  219. onUpdate: (target: cc.Node, ratio: number) => {
  220. //targetData.onUpdate && targetData.onUpdate.emit([target, ratio])
  221. if(targetData.onUpdate && targetData.onUpdate.length > 0)
  222. {
  223. for(let i = 0; i != targetData.onUpdate.length; ++i)
  224. {
  225. targetData.onUpdate[i].emit([target]);
  226. }
  227. }
  228. }
  229. }
  230. );
  231. }else
  232. {
  233. this.t = this.t.by(
  234. targetData.duration,
  235. toData,
  236. {
  237. easing: TweenEasing[this.tweenEasing] as any,
  238. onComplete: (target: cc.Node) => {
  239. console.log("----------tweenComplete");
  240. if(targetData.onComplete && targetData.onComplete.length > 0)
  241. {
  242. for(let i = 0; i != targetData.onComplete.length; ++i)
  243. {
  244. targetData.onComplete[i].emit([target]);
  245. }
  246. }
  247. //targetData.onComplete && targetData.onComplete.emit([target]);
  248. // this.edit_playing = false;
  249. // this._edit_play = false;
  250. },
  251. onStart: (target: cc.Node) => {
  252. console.log("----------tweenStart");
  253. //targetData.onStart && targetData.onStart.emit([target])
  254. if(targetData.onStart && targetData.onStart.length > 0)
  255. {
  256. for(let i = 0; i != targetData.onStart.length; ++i)
  257. {
  258. targetData.onStart[i].emit([target]);
  259. }
  260. }
  261. },
  262. onUpdate: (target: cc.Node, ratio: number) => {
  263. //targetData.onUpdate && targetData.onUpdate.emit([target, ratio])
  264. if(targetData.onUpdate && targetData.onUpdate.length > 0)
  265. {
  266. for(let i = 0; i != targetData.onUpdate.length; ++i)
  267. {
  268. targetData.onUpdate[i].emit([target]);
  269. }
  270. }
  271. }
  272. }
  273. );
  274. }
  275. }
  276. }
  277. if (this.onOneRepeatComplete) {
  278. this.t = this.t.call(() => {
  279. self.onOneRepeatComplete.emit([this, this.t])
  280. });
  281. }
  282. }
  283. }