123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- 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');
- }
- }
- }
|