import { _decorator, Component, Node, Label, Sprite, Button, resources, SpriteFrame, tween, Vec3, UIOpacity, UITransform, Color } from 'cc'; const { ccclass, property } = _decorator; @ccclass('PersonalInfoManager') export class PersonalInfoManager extends Component { @property({ type: Node, tooltip: '个人资料UI面板' }) personalInfoPanel: Node = null; @property({ type: Button, tooltip: '关闭按钮' }) closeButton: Button = null; @property({ type: Sprite, tooltip: '角色头像显示' }) characterAvatar: Sprite = null; @property({ type: Label, tooltip: '角色信息文本' }) infoText: Label = null; @property({ type: Label, tooltip: '角色姓名、房间号、ID等信息标签' }) nameInfoLabel: Label = null; @property({ tooltip: '动画时间(秒)', range: [0.1, 2.0, 0.1] }) animDuration: number = 0.5; // 当前显示的角色ID private currentCharacterId: number = -1; private panelOpacity: UIOpacity = null; start() { // 初始化隐藏面板 if (this.personalInfoPanel) { this.personalInfoPanel.active = false; // 确保面板有UIOpacity组件 this.panelOpacity = this.personalInfoPanel.getComponent(UIOpacity); if (!this.panelOpacity) { this.panelOpacity = this.personalInfoPanel.addComponent(UIOpacity); } } // 注册关闭按钮事件 this.setupCloseButton(); } private setupCloseButton() { if (this.closeButton) { this.closeButton.node.off('click'); this.closeButton.node.on('click', () => { this.hidePersonalInfoPanel(); }, this); } } /** * 显示个人资料面板 */ public showPersonalInfoPanel() { if (this.personalInfoPanel) { this.personalInfoPanel.active = true; this.personalInfoPanel.setSiblingIndex(999); // 播放从口袋拿出来的动画 this.playPocketOutAnimation(); } } /** * 播放从口袋掏出的动画 */ private playPocketOutAnimation() { // 设置初始状态 - 从右侧口袋拿出 this.personalInfoPanel.setScale(new Vec3(0.7, 0.2, 1)); // 扁平状态 this.personalInfoPanel.setPosition(new Vec3(200, -180, 0)); // 从右侧口袋位置开始 this.personalInfoPanel.setRotationFromEuler(new Vec3(0, 0, -20)); // 初始右倾斜角度 if (this.panelOpacity) { this.panelOpacity.opacity = 50; // 半透明开始 } // 创建动画 - 掏出口袋的感觉 tween(this.personalInfoPanel) // 先上移一点,同时展开 .to(this.animDuration * 0.6, { scale: new Vec3(0.9, 0.9, 1), position: new Vec3(100, -50, 0), eulerAngles: new Vec3(0, 0, -10) // 轻微倾斜,像是手拿着 }, { easing: 'quadOut' }) // 然后放到正确位置并恢复正常大小 .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.panelOpacity) { tween(this.panelOpacity) .to(this.animDuration * 0.7, { opacity: 255 }) .start(); } } /** * 隐藏个人资料面板 */ public hidePersonalInfoPanel() { if (this.personalInfoPanel) { // 播放放回口袋的动画 this.playPocketInAnimation(() => { this.personalInfoPanel.active = false; }); } } /** * 播放放回口袋的动画 */ private playPocketInAnimation(callback?: Function) { // 创建放回口袋的动画 tween(this.personalInfoPanel) // 先抬起并旋转 .to(this.animDuration * 0.3, { position: new Vec3(80, -30, 0), eulerAngles: new Vec3(0, 0, -10), scale: new Vec3(0.95, 0.95, 1) }, { easing: 'sineIn' }) // 然后放入口袋 .to(this.animDuration * 0.4, { position: new Vec3(200, -180, 0), eulerAngles: new Vec3(0, 0, -20), scale: new Vec3(0.6, 0.2, 1) // 扁平化,像塞入口袋 }, { easing: 'quadIn' }) .call(() => { if (callback) callback(); }) .start(); // 透明度动画 if (this.panelOpacity) { tween(this.panelOpacity) .to(this.animDuration * 0.6, { opacity: 0 }) .start(); } } /** * 显示角色资料 * @param data 包含角色资料的完整数据对象,由GameFlowManager提供 * 所需字段: * - characterId: 角色ID * - characterName: 角色名称 * - info: 个人资料文本 * - avatarPath: 头像路径 * - room: 房间号 * - identityId: 身份ID * - hasRoommate: 是否有室友 * - roommateInfo: 室友信息(可选) */ public displayCharacterInfo(data: any) { if (!data) { console.error('角色资料数据为空'); return; } console.log(`PersonalInfoManager.displayCharacterInfo: ID=${data.characterId}, 名称=${data.characterName}`); // 保存当前显示的角色ID this.currentCharacterId = data.characterId; // 设置文本信息 if (this.infoText && data.info) { this.infoText.string = data.info; } // 加载并设置头像 if (this.characterAvatar && data.avatarPath) { this.loadAvatar(data.avatarPath); } // 更新详细信息显示 this.updateDetailedInfo(data); // 显示面板 this.showPersonalInfoPanel(); } /** * 更新详细信息显示 * @param data 角色详细数据 */ private updateDetailedInfo(data: any) { if (!this.nameInfoLabel) return; // 构建详细信息文本 let detailedInfo = ''; // 添加姓名 if (data.characterName) { detailedInfo += `姓名: ${data.characterName}\n`; } // 添加房间号 if (data.room) { detailedInfo += `房间号: ${data.room}\n`; } // 添加ID if (data.identityId) { detailedInfo += `ID: ${data.identityId}\n`; } // 添加同住人信息 if (data.hasRoommate && data.roommateInfo) { detailedInfo += `同住人: ${data.roommateInfo}\n`; } else if (data.hasRoommate) { detailedInfo += `同住人: 有(未详)\n`; } else { detailedInfo += `同住人: 无\n`; } // 设置详细信息文本 this.nameInfoLabel.string = detailedInfo; } /** * 加载头像 * @param avatarPath 头像路径,PersonalInfo中的avatarPath */ private loadAvatar(avatarPath: string): void { if (!avatarPath) { console.error('头像路径为空'); this.loadDefaultAvatar(); return; } // 移除可能存在的.png后缀 const pathWithoutExtension = avatarPath.replace(/\.png$/, ''); // 构建正确的路径,确保以/spriteFrame结尾 const finalPath = pathWithoutExtension.endsWith('/spriteFrame') ? pathWithoutExtension : `${pathWithoutExtension}/spriteFrame`; console.log(`加载头像: ${finalPath}`); // 加载头像 resources.load(finalPath, SpriteFrame, (err, spriteFrame) => { if (err) { console.error(`加载头像失败: ${finalPath}`, err); this.loadDefaultAvatar(); return; } // 设置精灵帧 this.characterAvatar.spriteFrame = spriteFrame; console.log(`成功加载头像: ${finalPath}`); }); } /** * 加载默认头像 */ private loadDefaultAvatar(): void { console.log('加载默认头像'); // 使用内置资源或默认资源 const defaultIcon = "default_sprite"; resources.load(defaultIcon, SpriteFrame, (err, spriteFrame) => { if (err) { console.warn(`无法加载默认头像 ${defaultIcon}`, err); return; } this.characterAvatar.spriteFrame = spriteFrame; console.log('已设置默认头像'); }); } onDestroy() { if (this.closeButton) { this.closeButton.node.off('click'); } } }