docs: 为游戏地图模块添加详细的代码注释

为游戏地图模块的脚本文件添加全面的注释,说明每个组件的职责、关键设计、依赖关系和使用方式。注释覆盖了英雄信息面板、技能卡槽位管理器、排行榜弹窗、卡牌控制器、背景滚动组件等核心功能模块,提高了代码的可读性和维护性。

同时修复了英雄预制体的激活状态和技能效果预制体的尺寸参数。
This commit is contained in:
walkpan
2026-04-07 19:00:30 +08:00
parent 9a1d517aa9
commit e880613f8f
21 changed files with 1840 additions and 242 deletions

View File

@@ -1,3 +1,24 @@
/**
* @file IBoxComp.ts
* @description 英雄信息弹窗组件IBoxUI 视图层)
*
* 职责:
* 1. 作为全局弹窗,展示某个英雄的 **详细技能信息**。
* 2. 通过 onAdded(args) 接收英雄 UUID、等级和运行时技能数据。
* 3. 自动计算技能行数并动态调整弹窗背景高度和名称位置。
* 4. 点击弹窗任意区域关闭自身。
*
* 关键设计:
* - Line1~Line5 为预设的 5 行技能节点,按需显示/隐藏。
* - 每行包含技能名、等级、CD、描述文本和类型图标近战/远程/辅助)。
* - 背景高度 = baseHeight + (行数 - 1) × extraLineHeight。
* - 若传入 args.skills运行时技能优先使用否则回退到英雄静态配置。
*
* 依赖:
* - HeroInfoheroSet—— 英雄静态配置
* - SkillSet / ITypeSkillSet—— 技能静态配置
* - UIID —— 在 oops.gui 系统中注册的弹窗 ID
*/
import { _decorator, Label, Node, NodeEventType, UITransform } from "cc";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
@@ -6,9 +27,16 @@ import { IType, SkillSet } from "../common/config/SkillSet";
import { oops } from "db://oops-framework/core/Oops";
const { ccclass, property } = _decorator;
/**
* IBoxComp —— 英雄信息弹窗视图组件
*
* 通过 oops.gui.open(UIID.IBox, { heroUuid, heroLv, skills? }) 打开。
* 展示英雄技能列表,支持最多 5 行。
*/
@ccclass('IBoxComp')
@ecs.register('IBoxComp', false)
export class IBoxComp extends CCComp {
// ======================== 编辑器绑定节点5 行技能) ========================
@property(Node)
Line1: Node = null!
@property(Node)
@@ -19,11 +47,23 @@ export class IBoxComp extends CCComp {
Line4: Node = null!
@property(Node)
Line5: Node = null!
// ======================== 布局常量 ========================
/** 弹窗背景基础高度(只有 1 行技能时的高度) */
private readonly baseHeight: number = 100;
/** 每增加一行技能,背景增加的高度 */
private readonly extraLineHeight: number = 50;
/** 英雄名称标签的基准 Y 坐标 */
private readonly nameBaseY: number = 50;
/** 每增加一行技能,名称标签额外上移的 Y 偏移 */
private readonly nameExtraLineOffsetY: number = 25;
/**
* ECS 实体挂载回调:接收外部传入的英雄参数并渲染。
* @param args.heroUuid 英雄 UUID
* @param args.heroLv 英雄当前等级
* @param args.skills (可选)运行时技能数据,若无则使用英雄静态配置
*/
onAdded(args: {
heroUuid?: number;
heroLv?: number;
@@ -32,18 +72,32 @@ export class IBoxComp extends CCComp {
this.renderHeroInfo(args);
}
/** 绑定点击关闭事件 */
onLoad() {
this.node.on(NodeEventType.TOUCH_END, this.onTapClose, this);
}
/** 解绑点击事件 */
onDestroy() {
this.node.off(NodeEventType.TOUCH_END, this.onTapClose, this);
}
/** ECS 组件移除时销毁节点 */
reset() {
this.node.destroy();
}
// ======================== 渲染逻辑 ========================
/**
* 主渲染方法:解析英雄数据并填充技能行。
*
* 流程:
* 1. 从 args 中取英雄 UUID 和等级。
* 2. 优先使用运行时技能数据args.skills否则回退英雄静态配置。
* 3. 将每个技能映射为 { text, iType },过滤无效项。
* 4. 调用 applyLineData 渲染到 Line1~Line5。
*/
private renderHeroInfo(args: {
heroUuid?: number;
heroLv?: number;
@@ -58,13 +112,18 @@ export class IBoxComp extends CCComp {
return;
}
this.setHeroName(hero.name);
// 运行时技能 vs 静态配置
const runtimeSkills = args?.skills ? Object.values(args.skills) : [];
const sourceSkills = runtimeSkills.length > 0 ? runtimeSkills : Object.values(hero.skills ?? {});
// 将每个技能转换为显示数据
const lineData = sourceSkills.map(skill => {
const skillId = Math.floor(skill?.uuid ?? 0);
if (!skillId) return null;
const config = SkillSet[skillId];
if (!config) return null;
// 运行时技能直接使用其等级;静态配置的技能等级需叠加英雄等级修正
const runtimeLv = runtimeSkills.length > 0 ? Math.max(0, Math.floor(skill.lv ?? 0)) : Math.max(0, Math.floor((skill.lv ?? 1) + heroLv - 2));
const cd = Number(skill?.cd ?? 0);
return {
@@ -72,9 +131,18 @@ export class IBoxComp extends CCComp {
iType: config.IType
};
}).filter(item => !!item) as Array<{ text: string; iType: IType }>;
this.applyLineData(lineData.length > 0 ? lineData : [{ text: "暂无技能信息" }]);
}
/**
* 将技能数据应用到 Line1~Line5
* 1. 按顺序填充文本和类型图标。
* 2. 超出的行隐藏。
* 3. 根据显示行数调整弹窗高度和名称位置。
*
* @param skillLines 技能行数据数组
*/
private applyLineData(skillLines: Array<{ text: string; iType?: IType }>) {
const lines = [this.Line1, this.Line2, this.Line3, this.Line4, this.Line5];
const showCount = Math.max(1, Math.min(lines.length, skillLines.length));
@@ -86,16 +154,24 @@ export class IBoxComp extends CCComp {
if (!active) continue;
const data = skillLines[i];
const text = data?.text ?? "";
// 查找技能文本节点并设置内容
const noteNode = line.getChildByName("note");
const label = noteNode?.getComponent(Label) || noteNode?.getComponentInChildren(Label) || line.getComponentInChildren(Label);
if (label) label.string = text;
// 更新类型图标
this.updateLineTypeIcon(line, data?.iType);
}
// 动态调整弹窗背景高度
const targetHeight = this.baseHeight + Math.max(0, showCount - 1) * this.extraLineHeight;
this.updateIBoxHeight(targetHeight);
// 动态调整名称位置
this.updateNamePosition(showCount);
}
/**
* 设置弹窗背景 Bg 节点的高度
* @param height 目标高度
*/
private updateIBoxHeight(height: number) {
const bgNode = this.node.getChildByName("Bg");
const bgTransform = bgNode?.getComponent(UITransform);
@@ -104,6 +180,10 @@ export class IBoxComp extends CCComp {
}
}
/**
* 设置英雄名称标签
* @param name 英雄名称
*/
private setHeroName(name: string) {
const bgNode = this.node.getChildByName("Bg");
const nameNode = bgNode?.getChildByName("name");
@@ -114,6 +194,12 @@ export class IBoxComp extends CCComp {
}
}
/**
* 根据显示行数调整名称节点的 Y 坐标。
* 行数越多,名称越往上移,保持视觉居中。
*
* @param showCount 当前显示的技能行数
*/
private updateNamePosition(showCount: number) {
const bgNode = this.node.getChildByName("Bg");
const nameNode = bgNode?.getChildByName("name");
@@ -123,6 +209,11 @@ export class IBoxComp extends CCComp {
nameNode.setPosition(current.x, targetY, current.z);
}
/**
* 更新技能行的类型图标(互斥显示)。
* @param line 技能行节点
* @param iType 技能类型(近战 / 远程 / 辅助)
*/
private updateLineTypeIcon(line: Node, iType?: IType) {
const meleeNode = line.getChildByName("Melee");
const remoteNode = line.getChildByName("remote");
@@ -132,6 +223,7 @@ export class IBoxComp extends CCComp {
if (supportNode) supportNode.active = iType === IType.support;
}
/** 点击弹窗任意区域关闭自身 */
private onTapClose() {
oops.gui.removeByNode(this.node);
}