CharacterManager.ts 8.0 KB

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