RosterManager.ts 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. import { _decorator, Component, Node, Button, Animation, Sprite, SpriteFrame, resources, assetManager, Label, Layout, instantiate } from 'cc';
  2. const { ccclass, property } = _decorator;
  3. /**
  4. * 名单管理器,控制名单UI的显示和隐藏,并管理学生头像显示
  5. */
  6. @ccclass('RosterManager')
  7. export class RosterManager extends Component {
  8. @property({
  9. type: Node,
  10. tooltip: '名单UI面板'
  11. })
  12. rosterPanel: Node = null;
  13. @property({
  14. type: Button,
  15. tooltip: '关闭按钮'
  16. })
  17. closeButton: Button = null;
  18. @property({
  19. type: Animation,
  20. tooltip: '名单动画组件(可选)'
  21. })
  22. rosterAnimation: Animation = null;
  23. @property({
  24. type: Node,
  25. tooltip: '学生头像容器'
  26. })
  27. avatarContainer: Node = null;
  28. @property({
  29. tooltip: '头像资源路径'
  30. })
  31. avatarResourcePath: string = "avatars/";
  32. // 保存头像引用的字典
  33. private avatarMap: Map<string, SpriteFrame> = new Map();
  34. // 头像项预制体
  35. @property({
  36. type: Node,
  37. tooltip: '头像项预制体'
  38. })
  39. avatarItemPrefab: Node = null;
  40. start() {
  41. // 初始化隐藏名单面板
  42. if (this.rosterPanel) {
  43. this.rosterPanel.active = false;
  44. }
  45. // 注册关闭按钮点击事件
  46. this.setupCloseButton();
  47. }
  48. /**
  49. * 设置关闭按钮事件
  50. */
  51. private setupCloseButton() {
  52. if (this.closeButton) {
  53. // 移除可能已存在的事件监听
  54. this.closeButton.node.off('click');
  55. // 使用按钮的点击事件监听方式
  56. this.closeButton.node.on('click', () => {
  57. console.log('名单关闭按钮被点击');
  58. this.hideRosterPanel();
  59. }, this);
  60. console.log('名单关闭按钮事件已注册');
  61. } else {
  62. console.error('名单关闭按钮未设置');
  63. }
  64. }
  65. /**
  66. * 显示名单面板
  67. */
  68. public showRosterPanel() {
  69. if (this.rosterPanel) {
  70. this.rosterPanel.active = true;
  71. // 确保面板在最前面
  72. this.rosterPanel.setSiblingIndex(999);
  73. // 播放打开动画(如果有)
  74. if (this.rosterAnimation) {
  75. this.rosterAnimation.play('roster_open');
  76. }
  77. } else {
  78. console.error('名单面板未设置');
  79. }
  80. }
  81. /**
  82. * 隐藏名单面板
  83. */
  84. public hideRosterPanel() {
  85. console.log('hideRosterPanel被调用');
  86. if (this.rosterPanel) {
  87. // 播放关闭动画,并在动画结束后隐藏面板
  88. if (this.rosterAnimation) {
  89. this.rosterAnimation.play('roster_close');
  90. this.scheduleOnce(() => {
  91. this.rosterPanel.active = false;
  92. console.log('名单面板已隐藏(动画后)');
  93. }, 0.5); // 假设动画时长为0.5秒
  94. } else {
  95. this.rosterPanel.active = false;
  96. console.log('名单面板已隐藏(立即)');
  97. }
  98. }
  99. }
  100. /**
  101. * 预加载头像资源
  102. * @param avatarIds 头像ID数组
  103. */
  104. public preloadAvatars(avatarIds: string[]) {
  105. if (!this.avatarContainer) {
  106. return;
  107. }
  108. avatarIds.forEach(id => {
  109. const path = `${this.avatarResourcePath}avatar_${id}/spriteFrame`;
  110. resources.load(path, SpriteFrame, (err, spriteFrame) => {
  111. if (err) {
  112. console.error(`加载头像 ${id} 失败:`, err);
  113. return;
  114. }
  115. this.avatarMap.set(id, spriteFrame);
  116. });
  117. });
  118. }
  119. /**
  120. * 显示头像
  121. * @param slotId 头像位置ID
  122. * @param avatarId 头像资源ID
  123. */
  124. public showAvatar(slotId: string, avatarId: string) {
  125. if (!this.avatarContainer) {
  126. return;
  127. }
  128. // 查找对应的头像槽位
  129. const avatarSlot = this.avatarContainer.getChildByName(slotId);
  130. if (!avatarSlot) {
  131. console.error(`未找到头像槽位: ${slotId}`);
  132. return;
  133. }
  134. // 获取已加载的头像
  135. const spriteFrame = this.avatarMap.get(avatarId);
  136. if (spriteFrame) {
  137. const sprite = avatarSlot.getComponent(Sprite);
  138. if (sprite) {
  139. sprite.spriteFrame = spriteFrame;
  140. }
  141. } else {
  142. // 如果头像未预加载,则即时加载
  143. const path = `${this.avatarResourcePath}avatar_${avatarId}/spriteFrame`;
  144. resources.load(path, SpriteFrame, (err, spriteFrame) => {
  145. if (err) {
  146. console.error(`加载头像 ${avatarId} 失败:`, err);
  147. return;
  148. }
  149. const sprite = avatarSlot.getComponent(Sprite);
  150. if (sprite) {
  151. sprite.spriteFrame = spriteFrame;
  152. // 保存引用以便下次使用
  153. this.avatarMap.set(avatarId, spriteFrame);
  154. }
  155. });
  156. }
  157. }
  158. // 在RosterManager中添加处理关卡人员头像的方法
  159. public displayLevelPersonnel(personnelData: any[]) {
  160. console.log("开始显示人员列表...");
  161. console.log("avatarContainer:", this.avatarContainer);
  162. console.log("personnelData:", personnelData);
  163. if (!this.avatarContainer) {
  164. console.error('无法显示人员列表:avatarContainer未设置');
  165. return;
  166. }
  167. if (!personnelData || personnelData.length === 0) {
  168. console.error('无法显示人员列表:人员数据为空');
  169. return;
  170. }
  171. // 检查预制体
  172. if (!this.avatarItemPrefab) {
  173. console.error('头像项预制体未设置');
  174. return;
  175. }
  176. console.log("准备清空容器并创建新头像项");
  177. // 清空现有内容
  178. this.avatarContainer.removeAllChildren();
  179. // 遍历所有人员数据,创建头像项
  180. personnelData.forEach((person, index) => {
  181. // 创建新的头像项
  182. const avatarItem = instantiate(this.avatarItemPrefab);
  183. this.avatarContainer.addChild(avatarItem);
  184. // 设置姓名
  185. const nameLabel = avatarItem.getComponentInChildren(Label);
  186. if (nameLabel && person.name) {
  187. nameLabel.string = person.name;
  188. }
  189. // 使用完整的头像路径 - 直接从数据中获取
  190. if (person.avatarPath) {
  191. resources.load(person.avatarPath, SpriteFrame, (err, spriteFrame) => {
  192. if (err) {
  193. console.error(`加载头像失败: ${person.avatarPath}`, err);
  194. return;
  195. }
  196. // 查找头像显示组件
  197. const sprite = avatarItem.getComponentInChildren(Sprite);
  198. if (sprite) {
  199. sprite.spriteFrame = spriteFrame;
  200. }
  201. });
  202. }
  203. });
  204. // 更新布局
  205. const layout = this.avatarContainer.getComponent(Layout);
  206. if (layout) {
  207. this.scheduleOnce(() => {
  208. layout.updateLayout();
  209. }, 0.1);
  210. }
  211. }
  212. onDestroy() {
  213. // 移除按钮事件监听
  214. if (this.closeButton) {
  215. this.closeButton.node.off('click');
  216. }
  217. // 清理资源
  218. this.avatarMap.clear();
  219. }
  220. }