ResSpine.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import { IconUrl } from "../../data/const/ResConst";
  2. import { ResBaseAsset } from "./ResBaseAsset";
  3. const { ccclass, menu, disallowMultiple, requireComponent } = cc._decorator;
  4. /**
  5. * spine组件,自动管理资源的引用计数
  6. */
  7. @ccclass
  8. @disallowMultiple
  9. @requireComponent(sp.Skeleton)
  10. @menu("UI/ResSpine")
  11. export default class ResSpine extends ResBaseAsset<sp.SkeletonData> {
  12. private _spSkeleton: sp.Skeleton = null;
  13. private _url: string = '';
  14. get spSkeleton() {
  15. return this._spSkeleton || (this._spSkeleton = this.node?.getComponent(sp.Skeleton) || this.node?.addComponent(sp.Skeleton));
  16. }
  17. public get skeletonData() {
  18. return this.spSkeleton.skeletonData;
  19. }
  20. // private m_CompleteFunc: Function;
  21. /**
  22. * 通过 url 设置Spine
  23. * @param bundle
  24. * @param url spine动画 的json文件 路径
  25. * @param extraData
  26. * @returns
  27. */
  28. setSpineData<EXTRA_DATA = any>(bundle: string, url: string, cb?: (asset: sp.SkeletonData) => void, isPremultipliedAlpha: boolean = true, animationName: string = "standby", loop: boolean = true, speed: number = 1) {
  29. this._url = url;
  30. this.loadAsset(bundle, url, sp.SkeletonData, (asset: sp.SkeletonData) => {
  31. if (asset && this.spSkeleton && this.spSkeleton.isValid) {
  32. this.spSkeleton.skeletonData = asset;
  33. this.spSkeleton.enableBatch = true;
  34. this.spSkeleton.premultipliedAlpha = isPremultipliedAlpha;
  35. this.spSkeleton.loop = loop;
  36. if (this.spSkeleton.findAnimation(animationName) != null) {
  37. this.spSkeleton.animation = animationName;
  38. }
  39. this.spSkeleton.timeScale = speed;
  40. cb && cb(asset);
  41. } else {
  42. console.warn(`加载 Spine 失败: ${bundle} ${url}`);
  43. cb && cb(null);
  44. }
  45. });
  46. }
  47. setRoleSpine(url1: IconUrl, url2: string, cb?: (asset: sp.SkeletonData) => void, isPremultipliedAlpha: boolean = true, animationName: string = "standby", loop: boolean = true, speed: number = 1) {
  48. this.setSpineData("spine", url1 + url2 + "/" + url2, cb, isPremultipliedAlpha, animationName, loop, speed);
  49. }
  50. setAnimation(animationName: string) {
  51. if (this.spSkeleton) {
  52. this.spSkeleton.animation = animationName;
  53. }
  54. }
  55. /**
  56. * 播放动作
  57. * @param aniName 动画名称
  58. * @param loop 是否循环
  59. * @param showLast 显示最后一帧
  60. */
  61. playAnimation(aniName: string, loop: boolean, showLast?: boolean) {
  62. if (this.spSkeleton) {
  63. if (this.spSkeleton.findAnimation(aniName)) {
  64. this.spSkeleton.setAnimation(0, aniName, loop);
  65. if (showLast) {
  66. this.spSkeleton.timeScale = 100000;
  67. }
  68. } else {
  69. // console.error("动画名称不存在", this._url, aniName);
  70. }
  71. }
  72. }
  73. /** 是否存在动画 */
  74. isExistAnimation(aniName: string): boolean {
  75. return this.spSkeleton.findAnimation(aniName) ? true : false;
  76. }
  77. setTimeScale(speed: number) {
  78. if (this.spSkeleton) {
  79. this.spSkeleton.timeScale = speed;
  80. }
  81. }
  82. enableBatch() {
  83. this.spSkeleton.enableBatch = true;
  84. }
  85. clearTracks() {
  86. if (this.spSkeleton) {
  87. this.spSkeleton.clearTracks()
  88. }
  89. }
  90. clearRes() {
  91. this.spSkeleton.skeletonData = null;
  92. this.resetRes();
  93. }
  94. /** 设置渲染模式 */
  95. setCacheMode(mode: sp.Skeleton.AnimationCacheMode) {
  96. this.spSkeleton.setAnimationCacheMode(mode);
  97. }
  98. /** 后续废弃
  99. * 添加播放完成监听
  100. */
  101. addCompleteListener(callback: Function) {
  102. // this.m_CompleteFunc = callback;
  103. this.spSkeleton.setCompleteListener((trackEntry, loopCount) => {
  104. // this.spSkeleton.setCompleteListener(null);
  105. // if (this.m_CompleteFunc) this.m_CompleteFunc();
  106. // this.m_CompleteFunc = null;
  107. callback(trackEntry, loopCount);
  108. });
  109. }
  110. /**
  111. * 添加播放完成监听
  112. */
  113. AddSpineCompleteListener(callback: Function) {
  114. // this.m_CompleteFunc = callback;
  115. this.spSkeleton.setCompleteListener((trackEntry, loopCount) => {
  116. let name = trackEntry.animation ? trackEntry.animation.name : '';
  117. callback(name);
  118. });
  119. }
  120. /** 移除完成监听 */
  121. removeCompleteListener() {
  122. this.spSkeleton?.setCompleteListener(null);
  123. }
  124. /** 添加事件帧监听 */
  125. addEventListener(callback: Function): void {
  126. this.spSkeleton.setEventListener((trackIndex, event: any) => {
  127. let name = event.data.name;
  128. callback(name);
  129. });
  130. }
  131. /** 移除事件帧监听 */
  132. removeEventListener() {
  133. this.spSkeleton.setEventListener(null);
  134. }
  135. /** 获取插槽节点世界坐标 */
  136. getSlotWorldPos(slotName: string): cc.Vec2 {
  137. if (!slotName) return null;
  138. let slot: sp.spine.Slot = this.spSkeleton.findSlot(slotName);
  139. // 输出骨骼点的信息
  140. if (slot) {
  141. // 获取骨骼点的世界变换信息
  142. const worldX = slot.bone.worldX;
  143. const worldY = slot.bone.worldY;
  144. return this.node.convertToWorldSpaceAR(cc.v2(worldX, worldY)); //转换世界坐标
  145. } else {
  146. // console.error("未找到骨骼点: ", slotName);
  147. return null;
  148. }
  149. }
  150. /** 获取骨骼节点世界坐标 */
  151. getBoneWorldPos(boneName: string): cc.Vec2 {
  152. if (!boneName) return null;
  153. let bone: sp.spine.Bone = this.spSkeleton.findBone(boneName);
  154. // 输出骨骼点的信息
  155. if (bone) {
  156. // 获取骨骼点的世界变换信息
  157. const worldX = bone.worldX;
  158. const worldY = bone.worldY;
  159. return this.node.convertToWorldSpaceAR(cc.v2(worldX, worldY)); //转换世界坐标
  160. } else {
  161. // console.error("未找到骨骼点: ", boneName);
  162. return null;
  163. }
  164. }
  165. PauseAction() {
  166. if (this.spSkeleton && this.spSkeleton.isValid)
  167. this.spSkeleton.paused = true;
  168. }
  169. ResumeAction() {
  170. if (this.spSkeleton && this.spSkeleton.isValid)
  171. this.spSkeleton.paused = false;
  172. }
  173. StopAction() {
  174. if (this.spSkeleton && this.spSkeleton.isValid)
  175. this.spSkeleton.clearTracks();
  176. }
  177. }