refactor(ui): 重构英雄信息面板组件,提取通用逻辑
- 将 HInfoComp 重构为独立组件,封装标签查找与数据绑定逻辑 - 在 MissionCardComp 中使用 HInfoComp 替代直接操作 Label 组件 - 移除冗余的 findNodeByPath 和 resolvePanelLabel 方法 - 通过 isModelAlive 方法统一检查模型有效性
This commit is contained in:
@@ -190,7 +190,7 @@
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_useGrayscale": true,
|
||||
"_atlas": {
|
||||
"__uuid__": "6165ffc9-a838-4a33-b569-bdbaaab0e6b4",
|
||||
"__expectedType__": "cc.SpriteAtlas"
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user