import { _decorator, Component, Node, Button, Animation, Sprite, SpriteFrame, resources, assetManager, Label, Layout, instantiate, tween, Vec3, UIOpacity } from 'cc'; const { ccclass, property } = _decorator; /** * 名单管理器,控制名单UI的显示和隐藏,并管理学生头像显示 */ @ccclass('RosterManager') export class RosterManager extends Component { @property({ type: Node, tooltip: '名单UI面板' }) rosterPanel: Node = null; @property({ type: Button, tooltip: '关闭按钮' }) closeButton: Button = null; @property({ type: Animation, tooltip: '名单动画组件(可选)' }) rosterAnimation: Animation = null; @property({ type: Node, tooltip: '学生头像容器' }) avatarContainer: Node = null; @property({ tooltip: '头像资源路径' }) avatarResourcePath: string = "avatars/"; @property({ tooltip: '动画时间(秒)', range: [0.1, 2.0, 0.1] }) animDuration: number = 0.5; @property({ tooltip: '是否使用自定义动画', type: Boolean }) useCustomAnimation: boolean = true; // 保存头像引用的字典 private avatarMap: Map = new Map(); // 用于动画控制的组件 private rosterOpacity: UIOpacity = null; // 头像项预制体 @property({ type: Node, tooltip: '头像项预制体' }) avatarItemPrefab: Node = null; start() { // 初始化隐藏名单面板 if (this.rosterPanel) { this.rosterPanel.active = false; // 确保面板有UIOpacity组件 this.rosterOpacity = this.rosterPanel.getComponent(UIOpacity); if (!this.rosterOpacity) { this.rosterOpacity = this.rosterPanel.addComponent(UIOpacity); } } // 注册关闭按钮点击事件 this.setupCloseButton(); } /** * 设置关闭按钮事件 */ private setupCloseButton() { if (this.closeButton) { // 移除可能已存在的事件监听 this.closeButton.node.off('click'); // 使用按钮的点击事件监听方式 this.closeButton.node.on('click', () => { console.log('名单关闭按钮被点击'); this.hideRosterPanel(); }, this); console.log('名单关闭按钮事件已注册'); } else { console.error('名单关闭按钮未设置'); } } /** * 显示名单面板 */ public showRosterPanel() { if (this.rosterPanel) { this.rosterPanel.active = true; // 确保面板在最前面 this.rosterPanel.setSiblingIndex(999); // 判断使用哪种动画方式 if (this.useCustomAnimation) { // 使用自定义的口袋动画效果 this.playPocketOutAnimation(); } else if (this.rosterAnimation) { // 使用预设的动画组件 this.rosterAnimation.play('roster_open'); } } else { console.error('名单面板未设置'); } } /** * 播放从口袋掏出的动画 */ private playPocketOutAnimation() { // 设置初始状态 - 名单从左侧口袋掏出 this.rosterPanel.setScale(new Vec3(0.4, 0.2, 1)); // 扁平状态 this.rosterPanel.setPosition(new Vec3(-150, -250, 0)); // 从左下角(口袋位置)开始 this.rosterPanel.setRotationFromEuler(new Vec3(0, 0, 25)); // 初始倾斜角度,向左倾斜 if (this.rosterOpacity) { this.rosterOpacity.opacity = 50; // 半透明开始 } // 创建动画 - 掏出口袋的感觉 tween(this.rosterPanel) // 先抽出动作,有种抽纸张的感觉 .to(this.animDuration * 0.5, { scale: new Vec3(0.7, 0.8, 1), position: new Vec3(-100, -100, 0), eulerAngles: new Vec3(0, 0, 10) // 减少倾斜 }, { easing: 'cubicOut' }) // 然后放到正确位置 .to(this.animDuration * 0.4, { scale: new Vec3(1, 1, 1), position: new Vec3(0, 0, 0), eulerAngles: new Vec3(0, 0, 0) }, { easing: 'backOut' }) .start(); // 透明度动画 if (this.rosterOpacity) { tween(this.rosterOpacity) .to(this.animDuration * 0.7, { opacity: 255 }) .start(); } } /** * 隐藏名单面板 */ public hideRosterPanel() { console.log('hideRosterPanel被调用'); if (this.rosterPanel) { // 判断使用哪种动画方式 if (this.useCustomAnimation) { // 使用自定义的口袋动画效果 this.playPocketInAnimation(() => { this.rosterPanel.active = false; console.log('名单面板已隐藏(动画后)'); }); } else if (this.rosterAnimation) { // 使用预设的动画组件 this.rosterAnimation.play('roster_close'); this.scheduleOnce(() => { this.rosterPanel.active = false; console.log('名单面板已隐藏(动画后)'); }, 0.5); // 假设动画时长为0.5秒 } else { this.rosterPanel.active = false; console.log('名单面板已隐藏(立即)'); } } } /** * 播放放回口袋的动画 */ private playPocketInAnimation(callback?: Function) { // 创建放回口袋的动画 tween(this.rosterPanel) // 先抬起并旋转准备放回 .to(this.animDuration * 0.3, { position: new Vec3(-50, -50, 0), eulerAngles: new Vec3(0, 0, 15), scale: new Vec3(0.9, 0.9, 1) }, { easing: 'sineIn' }) // 然后塞入口袋 .to(this.animDuration * 0.4, { position: new Vec3(-150, -250, 0), eulerAngles: new Vec3(0, 0, 25), scale: new Vec3(0.4, 0.2, 1) // 扁平化,像塞入口袋 }, { easing: 'quadIn' }) .call(() => { if (callback) callback(); }) .start(); // 透明度动画 if (this.rosterOpacity) { tween(this.rosterOpacity) .to(this.animDuration * 0.6, { opacity: 0 }) .start(); } } /** * 预加载头像资源 * @param avatarIds 头像ID数组 */ public preloadAvatars(avatarIds: string[]) { if (!this.avatarContainer) { return; } avatarIds.forEach(id => { const path = `${this.avatarResourcePath}avatar_${id}/spriteFrame`; resources.load(path, SpriteFrame, (err, spriteFrame) => { if (err) { console.error(`加载头像 ${id} 失败:`, err); return; } this.avatarMap.set(id, spriteFrame); }); }); } /** * 显示头像 * @param slotId 头像位置ID * @param avatarId 头像资源ID */ public showAvatar(slotId: string, avatarId: string) { if (!this.avatarContainer) { return; } // 查找对应的头像槽位 const avatarSlot = this.avatarContainer.getChildByName(slotId); if (!avatarSlot) { console.error(`未找到头像槽位: ${slotId}`); return; } // 获取已加载的头像 const spriteFrame = this.avatarMap.get(avatarId); if (spriteFrame) { const sprite = avatarSlot.getComponent(Sprite); if (sprite) { sprite.spriteFrame = spriteFrame; } } else { // 如果头像未预加载,则即时加载 const path = `${this.avatarResourcePath}avatar_${avatarId}/spriteFrame`; resources.load(path, SpriteFrame, (err, spriteFrame) => { if (err) { console.error(`加载头像 ${avatarId} 失败:`, err); return; } const sprite = avatarSlot.getComponent(Sprite); if (sprite) { sprite.spriteFrame = spriteFrame; // 保存引用以便下次使用 this.avatarMap.set(avatarId, spriteFrame); } }); } } // 在RosterManager中添加处理关卡人员头像的方法 public displayLevelPersonnel(personnelData: any[]) { console.log("开始显示人员列表..."); console.log("avatarContainer:", this.avatarContainer); console.log("personnelData:", personnelData); if (!this.avatarContainer) { console.error('无法显示人员列表:avatarContainer未设置'); return; } if (!personnelData || personnelData.length === 0) { console.error('无法显示人员列表:人员数据为空'); return; } // 检查预制体 if (!this.avatarItemPrefab) { console.error('头像项预制体未设置'); return; } console.log("准备清空容器并创建新头像项"); // 清空现有内容 this.avatarContainer.removeAllChildren(); // 遍历所有人员数据,创建头像项 personnelData.forEach((person, index) => { // 创建新的头像项 const avatarItem = instantiate(this.avatarItemPrefab); this.avatarContainer.addChild(avatarItem); // 设置姓名 const nameLabel = avatarItem.getComponentInChildren(Label); if (nameLabel && person.name) { nameLabel.string = person.name; } // 使用完整的头像路径 - 直接从数据中获取 if (person.avatarPath) { resources.load(person.avatarPath, SpriteFrame, (err, spriteFrame) => { if (err) { console.error(`加载头像失败: ${person.avatarPath}`, err); return; } // 查找头像显示组件 const sprite = avatarItem.getComponentInChildren(Sprite); if (sprite) { sprite.spriteFrame = spriteFrame; } }); } }); // 更新布局 const layout = this.avatarContainer.getComponent(Layout); if (layout) { this.scheduleOnce(() => { layout.updateLayout(); }, 0.1); } } onDestroy() { // 移除按钮事件监听 if (this.closeButton) { this.closeButton.node.off('click'); } // 清理资源 this.avatarMap.clear(); } }