1. 为技能图标组件新增所属英雄UUID字段,传递英雄上下文 2. 在英雄列表面板中为技能图标绑定所属英雄ID 3. 新增英雄技能分档渲染逻辑,根据英雄等级展示对应技能解锁状态和描述 4. 补充注释和类型定义,完善代码文档
257 lines
9.8 KiB
TypeScript
257 lines
9.8 KiB
TypeScript
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 { EquipPoolList } from "../common/config/EquipSet";
|
||
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;
|
||
|
||
/**
|
||
* 技能小图标组件
|
||
*
|
||
* 由 MissSkillsComp.addSkill() 实例化并初始化。
|
||
* 在战场上以图标 + 剩余次数的形式呈现。
|
||
*/
|
||
@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,
|
||
card_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);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 初始化技能卡效果:
|
||
* 1. 从 EquipPoolList 查询装备卡的触发配置(含 trigger_type)。
|
||
* 2. 更新 UI 显示(图标 + 次数)。
|
||
*
|
||
* @param uuid 卡牌 UUID
|
||
* @param card_lv 技能卡等级
|
||
*/
|
||
init(uuid: number, card_lv: number) {
|
||
this.card_lv = card_lv;
|
||
|
||
// 装备卡配置已迁移至 EquipPoolList
|
||
const config = EquipPoolList.find(c => c.uuid === uuid);
|
||
if (config) {
|
||
this.s_uuid = config.skill ?? uuid; // 获取实际的技能 UUID
|
||
this.card_icon = config.icon; // 保存卡牌自定义图标(优先级最高)
|
||
this.trigger_type = config.trigger_type ?? CardTriggerType.Instant;
|
||
this.skill_name = config.name ?? "";
|
||
} else {
|
||
this.s_uuid = uuid;
|
||
this.skill_name = "";
|
||
}
|
||
|
||
this.updateUI();
|
||
}
|
||
|
||
/**
|
||
* 初始化英雄技能图标(英雄图鉴面板专用):
|
||
* 图标按 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();
|
||
}
|
||
}
|
||
}
|