feat: 新增技能装备详情弹窗IBox,替换旧英雄信息弹窗逻辑

1. 重构IBoxComp组件,支持技能和装备详情展示
2. 为EquipBoxComp和SkillBoxComp添加长按弹窗功能
3. 更新UI配置,修正IBox弹窗层级
4. 新增富文本工具函数生成技能装备详情文案
This commit is contained in:
pan
2026-07-31 10:55:46 +08:00
parent bdb4602fe6
commit 8c421c42d4
11 changed files with 2008 additions and 4222 deletions

View File

@@ -30,7 +30,7 @@
* - smc.mission —— 游戏运行状态
*/
import { mLogger } from "../common/Logger";
import { _decorator, Node, Sprite, Label, Vec3, tween, v3, Tween, NodeEventType } from "cc";
import { _decorator, Node, Prefab, Sprite, Label, Vec3, instantiate, tween, v3, Tween, NodeEventType } from "cc";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
import { CardTriggerType, CardConfig } from "../common/config/CardSet";
@@ -39,8 +39,8 @@ import { SkillOverrides } from "../common/config/SkillSet";
import { oops } from "db://oops-framework/core/Oops";
import { GameEvent } from "../common/config/GameEvent";
import { smc } from "../common/SingletonModuleComp";
import { UIID } from "../common/config/GameUIConfig";
import { getCardIconId, setSpriteFrame } from "../common/CardIconHelper";
import { IBoxComp } from "./IBoxComp";
const { ccclass, property } = _decorator;
/**
@@ -70,6 +70,13 @@ export class SkillBoxComp extends CCComp {
/** cd计时遮罩 */
@property({ type: Node })
private cd_mask: Node = null;
/** 技能详情弹窗预制体(长按图标时实例化展示) */
@property(Prefab)
private iboxPrefab: Prefab = null;
/** 当前已弹出的 IBox 实例(防止重复弹出) */
private iboxNode: Node = null;
// ======================== 技能配置 ========================
/** 技能 UUID */
@@ -149,6 +156,7 @@ export class SkillBoxComp extends CCComp {
}
// 清理长按计时器,防止销毁后回调访问失效节点
this.unschedule(this.showInfo);
this.closeInfoBox();
oops.message.off(GameEvent.NewWave, this.onNewWaveGlobal, this);
// 通知 MissSkillsComp 回收该节点占用的槽位
oops.message.dispatchEvent(GameEvent.RemoveSkillBox, this.node);
@@ -156,6 +164,8 @@ export class SkillBoxComp extends CCComp {
/** 长按时长(秒) */
private static readonly LONG_PRESS_TIME: number = 0.5;
/** IBox 相对图标的 Y 轴偏移(像素) */
private static readonly IBOX_OFFSET_Y: number = 80;
/** 信息框是否已弹出(区分长按完成与短按取消) */
private info_shown: boolean = false;
@@ -171,22 +181,58 @@ export class SkillBoxComp extends CCComp {
this.unschedule(this.showInfo);
if (this.info_shown) {
this.info_shown = false;
// oops.gui 移除信息框
oops.gui.remove(UIID.HInfo);
this.closeInfoBox();
}
}
/** 长按到点:弹出信息框 */
/** 长按到点:实例化 IBox 展示技能详情 */
private showInfo() {
if (!this.initialized) return;
mLogger.log(this.debugMode, "SkillBoxComp", "showInfo", {
initialized: this.initialized,
iboxPrefab: !!this.iboxPrefab,
s_uuid: this.s_uuid,
});
if (!this.initialized || !this.iboxPrefab) return;
this.closeInfoBox();
this.info_shown = true;
oops.audio.playEffect("music/button");
// 弹出 HInfoComp传入卡牌 UUID 和等级以启用预览模式
const config = SkillCardList.find(c => c.uuid === this.s_uuid || c.skill === this.s_uuid);
const cardUuid = config ? config.uuid : this.s_uuid;
oops.gui.remove(UIID.HInfo);
oops.gui.open(UIID.HInfo, { heroUuid: cardUuid, heroLv: this.card_lv, poolLv: config?.card_lv ?? 1, isSkillCard: true });
const config = SkillCardList.find(c => c.uuid === this.s_uuid || c.skill === this.s_uuid);
const skillUuid = config?.skill ?? this.s_uuid;
this.iboxNode = instantiate(this.iboxPrefab);
// 挂到技能图标的父节点下,使用局部坐标系
const parent = this.node.parent;
parent?.addChild(this.iboxNode);
// 弹窗宽度 720X 居中为 0Y 相对图标向上偏移
this.iboxNode.setPosition(0, this.node.position.y + SkillBoxComp.IBOX_OFFSET_Y, this.node.position.z);
mLogger.log(this.debugMode, "SkillBoxComp", "ibox instantiated", {
iboxNodeValid: this.iboxNode?.isValid,
iboxNodeActive: this.iboxNode?.active,
iboxNodePos: this.iboxNode?.position,
parentName: parent?.name,
});
const ibox = this.iboxNode.getComponent(IBoxComp);
mLogger.log(this.debugMode, "SkillBoxComp", "ibox component", {
hasIbox: !!ibox,
massageNode: ibox?.["massage_node"] ? "bound" : "null",
});
ibox?.init({
skillUuid,
skillLv: this.card_lv,
overrides: this.overrides,
});
mLogger.log(this.debugMode, "SkillBoxComp", "ibox init done", {
iboxNodePos: this.iboxNode?.position,
});
}
/** 关闭并清理已弹出的 IBox */
private closeInfoBox() {
if (this.iboxNode && this.iboxNode.isValid) {
this.iboxNode.destroy();
}
this.iboxNode = null;
}
/**