Files
pixelheros/assets/script/game/map/SSkillBoxComp.ts
panFD 10a6d18836 refactor(skill-text): 重构技能文案系统,拆分英雄/卡牌语境
1.  将原HeroSkillDesc拆分为CardSkillText(卡牌/道具通用)和HeroSkillText(英雄专属)
2.  移除废弃的HeroSkillDesc文件与相关引用
3.  统一技能文案生成逻辑,修复数值漂移问题
4.  调整英雄配置中技能解锁等级与分档规则
5.  优化技能弹窗UI与参数传递逻辑
2026-08-28 08:36:39 +08:00

230 lines
8.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<number, string> = {
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();
}
}
}