import { _decorator, Node, Sprite, Label, 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 { oops } from "db://oops-framework/core/Oops"; import { CardTriggerType } from "../common/config/CardSet"; import { SkillSet, FieldSkillSet } from "../common/config/SkillSet"; import { FieldEntry } from "../common/config/heroSet"; import { UIID } from "../common/config/GameUIConfig"; import { smc } from "../common/SingletonModuleComp"; const { ccclass, property } = _decorator; /** * 技能小图标组件 * * 由英雄图鉴面板(HerosListComp.addSkillIcon)实例化, * 以图标 + 技能等级 + 锁定遮罩的形式展示英雄技能,点击弹出技能信息框。 */ @ccclass('SSkillBoxComp') @ecs.register('SSkillBoxComp', false) export class SSkillBoxComp extends CCComp { /** 技能图标节点 */ @property({ type: Node }) private icon_node: Node = null; /** 技能图标节点:下面有 green blue purple red yellow 5个不同颜色节点*/ @property({ type: Node }) private bg_node: Node = null; /** 技能等级标签 */ @property(Label) private lv_label: Label = null; /** 技能名称标签 */ @property(Label) private name_label: Label = null; /** 锁定遮罩节点(active 时表示技能未激活) */ @property({ type: Node }) private locked: Node = null; /** 技能 UUID */ private s_uuid: number = 0; /** 所属英雄 UUID(英雄图鉴模式,>0 时点击弹窗走英雄技能分档描述) */ private hero_uuid: number = 0; /** 卡牌等级 */ private card_lv: number = 1; /** 卡牌自定义图标ID(优先级最高,未定义则按 trigger_type 自动取) */ private card_icon?: string; /** 技能名称(装备卡取卡牌名,英雄图鉴取技能名) */ private skill_name: string = ""; /** 触发类型(默认即时,保持向后兼容) */ private trigger_type: CardTriggerType = CardTriggerType.Instant; /** 驻场技能词条列表(uuid 指向 FieldSkillSet 底座,value 为生效数值) */ public field: FieldEntry[] = []; /** 英雄图鉴模式下的图标来源:skill=SkillSet,field=FieldSkillSet;undefined 表示装备卡模式 */ private hero_icon_source?: "skill" | "field"; /** 点击事件是否已注册(防止重复绑定) */ private _clickRegistered: boolean = false; /** * 注册点击事件(幂等,可安全重复调用) */ private registerClick() { if (this._clickRegistered) return; this._clickRegistered = true; this.node.on(NodeEventType.TOUCH_END, this.onClick, this); } /** 点击:弹出技能信息框 */ private onClick() { oops.audio.playEffect("music/button"); oops.gui.open(UIID.SInfo, { uuid: this.s_uuid, skill_lv: this.card_lv, card_icon: this.card_icon, skill_name: this.resolveSkillName(), field: this.field, trigger_type: this.trigger_type, // 英雄图鉴模式:携带所属英雄,弹窗按英雄技能分档描述渲染 hero_uuid: this.hero_uuid || undefined, }); } onLoad() { this.registerClick(); } onDestroy() { super.onDestroy(); if (this.node && this.node.isValid) { this.node.off(NodeEventType.TOUCH_END, this.onClick, this); } } /** * 初始化英雄技能图标(英雄图鉴面板专用): * 图标按 s_uuid 直接取 SkillSet / FieldSkillSet 配置,不走 EquipPoolList。 * @param s_uuid 技能 UUID(大招/触发技能指向 SkillSet,光环词条指向 FieldSkillSet) * @param s_lv 当前英雄等级下生效的技能等级(显示在等级标签) * @param locked 当前等级未激活时显示锁定遮罩 * @param isField true 时图标取 FieldSkillSet(驻场光环词条) * @param heroUuid 所属英雄 UUID(点击弹窗按英雄技能分档描述渲染) */ initHeroSkill(s_uuid: number, s_lv: number, locked: boolean, isField: boolean = false, heroUuid: number = 0) { this.s_uuid = s_uuid; this.hero_uuid = heroUuid; this.card_lv = s_lv; this.hero_icon_source = isField ? "field" : "skill"; this.updateUI(); this.setLocked(locked); } /** * 设置技能激活状态: * - locked = true → 显示锁定遮罩,技能未激活(隐藏等级标签) * - locked = false → 隐藏锁定遮罩,技能已激活(恢复等级标签) */ setLocked(locked: boolean) { if (this.locked) { this.locked.active = locked; } if (this.lv_label) { this.lv_label.node.active = !locked; } } /** * 根据技能等级切换 bg_node 下的颜色子节点显示。 * 等级与颜色对应关系: * 技能卡档位:card_lv 1 (wave 1) → green,2 (wave 5) → blue,3 (wave 8) → purple * 英雄技能等级:s_lv 1~5 → green / blue / purple / red / yellow */ private updateBgNode() { if (!this.bg_node) return; const lvToColor: Record = { 1: "green", 2: "blue", 3: "purple", 4: "red", 5: "yellow", }; const targetColor = lvToColor[this.card_lv]; this.bg_node.children.forEach(child => { child.active = (child.name === targetColor); }); } /** * 解析技能名称: * 优先取显式设置的卡牌名;否则按图标来源从 SkillSet / FieldSkillSet 取技能名。 */ private resolveSkillName(): string { if (this.skill_name) return this.skill_name; if (this.hero_icon_source === "field") { return this.s_uuid ? (FieldSkillSet[this.s_uuid]?.name ?? "") : ""; } if (this.hero_icon_source === "skill") { return this.s_uuid ? (SkillSet[this.s_uuid]?.name ?? "") : ""; } if (this.trigger_type === CardTriggerType.Interval) { return this.s_uuid ? (SkillSet[this.s_uuid]?.name ?? "") : ""; } if (this.trigger_type === CardTriggerType.Field) { const fieldUuid = this.field?.[0]?.uuid; return fieldUuid ? (FieldSkillSet[fieldUuid]?.name ?? "") : ""; } return ""; } /** * 更新 UI: * - 背景:根据技能等级切换对应颜色子节点显示 * - 图标:从 uicons 图集获取 * - 名称标签:显示技能名称 * - 等级标签:显示技能等级(Lv.x 样式) */ updateUI() { // 按技能等级切换背景颜色节点(与 getLvColor 等级配色一致) this.updateBgNode(); // 加载技能图标 if (this.icon_node) { // 优先使用卡牌自定义 icon;未定义则按图鉴模式 / 装备卡 trigger_type 自动取 let iconId: string | undefined = this.card_icon; if (!iconId) { if (this.hero_icon_source === "field") { // 英雄图鉴:驻场光环词条图标取 FieldSkillSet iconId = this.s_uuid ? FieldSkillSet[this.s_uuid]?.icon : undefined; } else if (this.hero_icon_source === "skill") { // 英雄图鉴:大招/触发技能图标取 SkillSet iconId = this.s_uuid ? SkillSet[this.s_uuid]?.icon : undefined; } else if (this.trigger_type === CardTriggerType.Interval) { iconId = this.s_uuid ? SkillSet[this.s_uuid]?.icon : undefined; } else if (this.trigger_type === CardTriggerType.Field) { const fieldUuid = this.field?.[0]?.uuid; iconId = fieldUuid ? FieldSkillSet[fieldUuid]?.icon : undefined; } } if (this.icon_node && this.icon_node.isValid) { let sprite = this.icon_node.getComponent(Sprite) || this.icon_node.addComponent(Sprite); if (smc.uiconsAtlas && iconId) { const frame = smc.uiconsAtlas.getSpriteFrame(iconId); sprite.spriteFrame = frame || null; // 取不到时清空,避免残留 } else { sprite.spriteFrame = null; } } } // 显示技能名称 if (this.name_label) { this.name_label.string = this.resolveSkillName(); } // 显示技能等级(Lv.x 样式) if (this.lv_label) { this.lv_label.string = `Lv.${this.card_lv}`; } } /** ECS 组件移除时销毁节点 */ reset() { if (this.node && this.node.isValid) { this.node.destroy(); } } }