refactor(ui): 重构英雄信息面板组件,提取通用逻辑

- 将 HInfoComp 重构为独立组件,封装标签查找与数据绑定逻辑
- 在 MissionCardComp 中使用 HInfoComp 替代直接操作 Label 组件
- 移除冗余的 findNodeByPath 和 resolvePanelLabel 方法
- 通过 isModelAlive 方法统一检查模型有效性
This commit is contained in:
panw
2026-03-25 17:26:51 +08:00
parent de90dadaed
commit 80bf8efc30
3 changed files with 66 additions and 36 deletions

View File

@@ -190,7 +190,7 @@
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_useGrayscale": false,
"_useGrayscale": true,
"_atlas": {
"__uuid__": "6165ffc9-a838-4a33-b569-bdbaaab0e6b4",
"__expectedType__": "cc.SpriteAtlas"

View File

@@ -1,20 +1,66 @@
import { mLogger } from "../common/Logger";
import { _decorator, Animation, AnimationClip, EventTouch, Label, Node, NodeEventType, Sprite, SpriteAtlas, Tween, tween, UIOpacity, Vec3, resources } from "cc";
import { _decorator, Label, Node } 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 { HeroAttrsComp } from "../hero/HeroAttrsComp";
const { ccclass, property } = _decorator;
const { ccclass } = _decorator;
/** 视图层对象 */
@ccclass('HInfoComp')
@ecs.register('HInfoComp', false)
export class HInfoComp extends CCComp {
private debugMode: boolean = true;
/** 锁定态图标节点(显示时表示本槽位锁定) */
private eid: number = 0;
private model: HeroAttrsComp | null = null;
private apLabel: Label | null = null;
private hpLabel: Label | null = null;
onLoad() {
this.cacheLabels();
}
bindData(eid: number, model: HeroAttrsComp) {
this.eid = eid;
this.model = model;
this.cacheLabels();
this.refresh();
}
refresh() {
if (!this.model) return;
if (this.apLabel) {
this.apLabel.string = `${Math.max(0, Math.floor(this.model.ap ?? 0))}`;
}
if (this.hpLabel) {
this.hpLabel.string = `${Math.max(0, Math.floor(this.model.hp_max ?? 0))}`;
}
}
isModelAlive(): boolean {
return !!(this.model as any)?.ent;
}
private cacheLabels() {
if (!this.apLabel) {
this.apLabel = this.findLabelByPath(["ap", "val"]);
}
if (!this.hpLabel) {
this.hpLabel = this.findLabelByPath(["hp", "val"]);
}
}
private findLabelByPath(path: string[]): Label | null {
let current: Node | null = this.node;
for (let i = 0; i < path.length; i++) {
current = current?.getChildByName(path[i]) ?? null;
if (!current) return null;
}
return current.getComponent(Label) || current.getComponentInChildren(Label);
}
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
reset() {
this.model = null;
this.eid = 0;
this.node.destroy();
}
}

View File

@@ -8,6 +8,7 @@ import { smc } from "../common/SingletonModuleComp";
import { CardComp } from "./CardComp";
import { oops } from "db://oops-framework/core/Oops";
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
import { HInfoComp } from "./HInfoComp";
const { ccclass, property } = _decorator;
@@ -54,8 +55,7 @@ export class MissionCardComp extends CCComp {
private heroInfoItems: Map<number, {
node: Node,
model: HeroAttrsComp,
apLabel: Label | null,
hpLabel: Label | null
comp: HInfoComp
}> = new Map();
onLoad() {
/** 绑定事件 -> 缓存子控制器 -> 初始化UI状态 */
@@ -372,18 +372,24 @@ export class MissionCardComp extends CCComp {
const current = this.heroInfoItems.get(eid);
if (current) {
current.model = model;
current.comp.bindData(eid, model);
this.updateHeroInfoPanel(current);
return;
}
const node = instantiate(this.hero_info_prefab);
node.parent = this.hero_info_node;
node.active = true;
const comp = node.getComponent(HInfoComp);
if (!comp) {
node.destroy();
return;
}
const item = {
node,
model,
apLabel: this.resolvePanelLabel(node, [["ap", "val"]]),
hpLabel: this.resolvePanelLabel(node, [["hp", "val"]])
comp
};
comp.bindData(eid, model);
this.heroInfoItems.set(eid, item);
this.relayoutHeroInfoPanels();
this.updateHeroInfoPanel(item);
@@ -396,8 +402,7 @@ export class MissionCardComp extends CCComp {
removeKeys.push(eid);
return;
}
const ent = (item.model as any)?.ent;
if (!ent) {
if (!item.comp.isModelAlive()) {
if (item.node.isValid) item.node.destroy();
removeKeys.push(eid);
return;
@@ -415,11 +420,9 @@ export class MissionCardComp extends CCComp {
private updateHeroInfoPanel(item: {
node: Node,
model: HeroAttrsComp,
apLabel: Label | null,
hpLabel: Label | null
comp: HInfoComp
}) {
if (item.apLabel) item.apLabel.string = `${Math.max(0, Math.floor(item.model.ap ?? 0))}`;
if (item.hpLabel) item.hpLabel.string = `${Math.max(0, Math.floor(item.model.hp_max ?? 0))}`;
item.comp.refresh();
}
private relayoutHeroInfoPanels() {
@@ -448,25 +451,6 @@ export class MissionCardComp extends CCComp {
this.heroInfoSyncTimer = 0;
}
private resolvePanelLabel(root: Node, paths: string[][]): Label | null {
for (let i = 0; i < paths.length; i++) {
const node = this.findNodeByPath(root, paths[i]);
if (!node) continue;
const label = node.getComponent(Label) || node.getComponentInChildren(Label);
if (label) return label;
}
return null;
}
private findNodeByPath(root: Node, path: string[]): Node | null {
let current: Node | null = root;
for (let i = 0; i < path.length; i++) {
current = current?.getChildByName(path[i]) ?? null;
if (!current) return null;
}
return current;
}
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
reset() {
this.clearHeroInfoPanels();