CharacterManager.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. import { _decorator, Component, Node, Button, Vec3, tween, Tween, resources, sp } from 'cc';
  2. import { DialogueManager } from './DialogueManager';
  3. const { ccclass, property } = _decorator;
  4. @ccclass('CharacterManager')
  5. export class CharacterManager extends Component {
  6. @property({
  7. type: DialogueManager,
  8. tooltip: '对话框管理器'
  9. })
  10. dialogueManager: DialogueManager = null;
  11. @property({
  12. type: Node,
  13. tooltip: '人物节点'
  14. })
  15. characterNode: Node = null;
  16. @property({
  17. type: Button,
  18. tooltip: '放行按钮(向右移动)'
  19. })
  20. letPassButton: Button = null;
  21. @property({
  22. type: Button,
  23. tooltip: '赶走按钮(向左移动)'
  24. })
  25. dismissButton: Button = null;
  26. @property({
  27. tooltip: '人物移动动画持续时间(秒)'
  28. })
  29. moveDuration: number = 1.0;
  30. @property({
  31. tooltip: '人物移动距离(像素)'
  32. })
  33. moveDistance: number = 300;
  34. private initialPosition: Vec3 = null;
  35. private currentAnimation: Tween<Node> = null;
  36. start() {
  37. // 记录人物初始位置
  38. if (this.characterNode) {
  39. this.initialPosition = this.characterNode.position.clone();
  40. }
  41. // 设置按钮事件监听
  42. if (this.letPassButton) {
  43. this.letPassButton.node.on(Button.EventType.CLICK, this.moveCharacterRight, this);
  44. }
  45. if (this.dismissButton) {
  46. this.dismissButton.node.on(Button.EventType.CLICK, this.moveCharacterLeft, this);
  47. }
  48. }
  49. /**
  50. * 设置角色外观
  51. * @param characterId 角色ID
  52. * @param skinName 皮肤名称
  53. * @param onComplete 外观设置完成后的回调函数
  54. */
  55. public setupCharacterAppearance(characterId: number, skinName: string, onComplete?: () => void): void {
  56. if (!this.characterNode) {
  57. console.error('人物节点未设置');
  58. return;
  59. }
  60. // 构建角色资源路径(左边补0确保两位数)
  61. const characterFolderName = characterId < 10 ? `0${characterId}` : `${characterId}`;
  62. const characterPath = `${characterFolderName}`;
  63. // 加载角色骨骼动画资源
  64. resources.load(`${characterPath}/${characterId}`, sp.SkeletonData, (err, skeletonData) => {
  65. if (err) {
  66. console.error(`加载角色资源失败: ${characterPath}/${characterId}`, err);
  67. return;
  68. }
  69. // 获取骨骼动画组件
  70. const skeletonComponent = this.characterNode.getComponent(sp.Skeleton);
  71. if (skeletonComponent) {
  72. // 设置骨骼数据
  73. skeletonComponent.skeletonData = skeletonData;
  74. skeletonComponent.setSkin(skinName);
  75. skeletonComponent.setAnimation(0, 'loop', true);
  76. console.log(`设置角色: ${characterId}, 皮肤: ${skinName}`);
  77. // 如果有回调函数,则在设置完成后调用
  78. if (onComplete) {
  79. onComplete();
  80. }
  81. } else {
  82. console.error('人物节点上没有sp.Skeleton组件');
  83. }
  84. });
  85. }
  86. /**
  87. * 人物移动到右侧(放行)
  88. * @param onComplete 移动完成后的回调函数
  89. */
  90. public moveCharacterRight(onComplete?: () => void): void {
  91. if (!this.characterNode || !this.initialPosition) return;
  92. // 隐藏对话框
  93. if (this.dialogueManager) {
  94. this.dialogueManager.hideDialogue();
  95. }
  96. // 停止当前动画
  97. if (this.currentAnimation) {
  98. this.currentAnimation.stop();
  99. }
  100. // 目标位置:向右移动
  101. const targetPos = new Vec3(
  102. this.initialPosition.x + this.moveDistance,
  103. this.initialPosition.y,
  104. this.initialPosition.z
  105. );
  106. // 创建动画
  107. this.currentAnimation = tween(this.characterNode)
  108. .to(this.moveDuration, { position: targetPos }, { easing: 'cubicOut' })
  109. .call(() => {
  110. // 动画完成回调
  111. this.currentAnimation = null;
  112. // 如果有完成回调则执行
  113. if (onComplete) {
  114. onComplete();
  115. }
  116. })
  117. .start();
  118. }
  119. /**
  120. * 人物移动到左侧(赶走)
  121. * @param onComplete 移动完成后的回调函数
  122. */
  123. public moveCharacterLeft(onComplete?: () => void): void {
  124. if (!this.characterNode || !this.initialPosition) return;
  125. // 隐藏对话框
  126. if (this.dialogueManager) {
  127. this.dialogueManager.hideDialogue();
  128. }
  129. // 停止当前动画
  130. if (this.currentAnimation) {
  131. this.currentAnimation.stop();
  132. }
  133. // 目标位置:向左移动
  134. const targetPos = new Vec3(
  135. this.initialPosition.x - this.moveDistance,
  136. this.initialPosition.y,
  137. this.initialPosition.z
  138. );
  139. // 创建动画
  140. this.currentAnimation = tween(this.characterNode)
  141. .to(this.moveDuration, { position: targetPos }, { easing: 'cubicOut' })
  142. .call(() => {
  143. // 动画完成回调
  144. this.currentAnimation = null;
  145. // 如果有完成回调则执行
  146. if (onComplete) {
  147. onComplete();
  148. }
  149. })
  150. .start();
  151. }
  152. /**
  153. * 新人物从左向右进入
  154. * @param onComplete 移动完成后的回调函数
  155. */
  156. public characterEnter(onComplete?: () => void): void {
  157. console.log('characterEnter');
  158. if (!this.characterNode) return;
  159. // 隐藏对话框
  160. if (this.dialogueManager) {
  161. this.dialogueManager.hideDialogue();
  162. }
  163. // 停止当前动画
  164. if (this.currentAnimation) {
  165. this.currentAnimation.stop();
  166. }
  167. // 设置起始位置(在左侧)
  168. const startPos = new Vec3(
  169. this.initialPosition.x - this.moveDistance,
  170. this.initialPosition.y,
  171. this.initialPosition.z
  172. );
  173. this.characterNode.position = startPos;
  174. // 创建动画,移动到初始位置
  175. this.currentAnimation = tween(this.characterNode)
  176. .to(this.moveDuration, { position: this.initialPosition }, { easing: 'cubicOut' })
  177. .call(() => {
  178. // 动画完成回调
  179. this.currentAnimation = null;
  180. // 如果有完成回调则执行
  181. if (onComplete) {
  182. onComplete();
  183. }
  184. })
  185. .start();
  186. }
  187. /**
  188. * 重置人物位置到初始位置
  189. */
  190. public resetCharacterPosition(): void {
  191. if (this.characterNode && this.initialPosition) {
  192. // 停止当前动画
  193. if (this.currentAnimation) {
  194. this.currentAnimation.stop();
  195. this.currentAnimation = null;
  196. }
  197. // 直接设置到初始位置
  198. this.characterNode.position = this.initialPosition.clone();
  199. }
  200. }
  201. onDestroy() {
  202. // 移除按钮事件监听
  203. if (this.letPassButton) {
  204. this.letPassButton.node.off(Button.EventType.CLICK, this.moveCharacterRight, this);
  205. }
  206. if (this.dismissButton) {
  207. this.dismissButton.node.off(Button.EventType.CLICK, this.moveCharacterLeft, this);
  208. }
  209. }
  210. }