CharacterManager.ts 7.6 KB

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