refactor(map): 优化英雄信息面板的缓存与复用逻辑
1. 新增缓存预先放置的HInfoComp组件,避免运行时实例化预制体 2. 移除动态创建面板逻辑,改为复用预先摆放的节点 3. 简化ensureHeroInfoPanel逻辑,通过node_index直接获取目标组件 4. 销毁时改为隐藏缓存节点而非直接销毁,保留复用基础 5. 移除冗余的relayoutHeroInfoPanels方法和相关逻辑
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -150,6 +150,8 @@ export class MissionCardComp extends CCComp {
|
||||
model: HeroAttrsComp,
|
||||
comp: HInfoComp
|
||||
}> = new Map();
|
||||
/** 缓存预先放置的 6 个 HInfoComp */
|
||||
private cachedHInfoComps: Map<number, HInfoComp> = new Map();
|
||||
// ======================== 生命周期 ========================
|
||||
|
||||
/**
|
||||
@@ -161,6 +163,7 @@ export class MissionCardComp extends CCComp {
|
||||
* 5. 触发首次任务开始流程。
|
||||
*/
|
||||
onLoad() {
|
||||
this.cacheHInfoComps();
|
||||
this.bindEvents();
|
||||
this.cacheCardComps();
|
||||
this.layoutCardSlots();
|
||||
@@ -171,6 +174,19 @@ export class MissionCardComp extends CCComp {
|
||||
poolLv: this.poolLv
|
||||
});
|
||||
}
|
||||
|
||||
private cacheHInfoComps() {
|
||||
this.cachedHInfoComps.clear();
|
||||
if (!this.hero_info_node) return;
|
||||
for (let i = 0; i < this.hero_info_node.children.length; i++) {
|
||||
const child = this.hero_info_node.children[i];
|
||||
const comp = (child.getComponent(HInfoComp) || child.getComponent("HInfoComp")) as HInfoComp;
|
||||
if (comp && comp.node_index > 0) {
|
||||
this.cachedHInfoComps.set(comp.node_index, comp);
|
||||
child.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 组件销毁时解绑所有事件并清理英雄信息面板 */
|
||||
onDestroy() {
|
||||
@@ -880,48 +896,44 @@ export class MissionCardComp extends CCComp {
|
||||
}
|
||||
|
||||
private ensureHeroInfoPanel(eid: number, model: HeroAttrsComp) {
|
||||
if (!this.hero_info_node || !this.hero_info_prefab) {
|
||||
mLogger.error(this.debugMode, "MissionCardComp", "ensureHeroInfoPanel: missing hero_info_node or hero_info_prefab");
|
||||
if (!this.hero_info_node) {
|
||||
mLogger.error(this.debugMode, "MissionCardComp", "ensureHeroInfoPanel: missing hero_info_node");
|
||||
return;
|
||||
}
|
||||
this.hero_info_node.active = true;
|
||||
|
||||
// 计算目标 node_index: lane_index=0 对应 1排(1-3), lane_index=1 对应 2排(4-6)
|
||||
// lane=0 上路, lane=1 中路, lane=2 下路
|
||||
const expectedNodeIndex = model.lane_index * 3 + model.lane + 1;
|
||||
const comp = this.cachedHInfoComps.get(expectedNodeIndex);
|
||||
|
||||
if (!comp) {
|
||||
mLogger.error(this.debugMode, "MissionCardComp", `ensureHeroInfoPanel: missing pre-placed HInfoComp for index ${expectedNodeIndex}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const current = this.heroInfoItems.get(eid);
|
||||
if (current) {
|
||||
current.model = model;
|
||||
current.comp.bindData(eid, model);
|
||||
current.comp = comp;
|
||||
current.node = comp.node;
|
||||
comp.node.active = true;
|
||||
comp.bindData(eid, model);
|
||||
this.updateHeroInfoPanel(current);
|
||||
return;
|
||||
}
|
||||
|
||||
mLogger.log(this.debugMode, "MissionCardComp", "ensureHeroInfoPanel: creating new panel for eid", eid);
|
||||
const node = instantiate(this.hero_info_prefab);
|
||||
node.parent = this.hero_info_node;
|
||||
node.active = true;
|
||||
|
||||
// 尝试两种方式获取组件,并输出日志
|
||||
let comp = node.getComponent(HInfoComp) as any;
|
||||
if (!comp) {
|
||||
comp = node.getComponent("HInfoComp") as any;
|
||||
}
|
||||
|
||||
if (!comp) {
|
||||
mLogger.error(this.debugMode, "MissionCardComp", "ensureHeroInfoPanel: Failed to get HInfoComp from prefab!");
|
||||
node.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
comp.node.active = true;
|
||||
const item = {
|
||||
node,
|
||||
node: comp.node,
|
||||
model,
|
||||
comp
|
||||
};
|
||||
comp.bindData(eid, model);
|
||||
comp.setBattlePhase(this.isBattlePhase);
|
||||
this.heroInfoItems.set(eid, item);
|
||||
this.relayoutHeroInfoPanels();
|
||||
this.updateHeroInfoPanel(item);
|
||||
|
||||
mLogger.log(this.debugMode, "MissionCardComp", `ensureHeroInfoPanel: new panel created for eid ${eid}, final position:`, item.node.position);
|
||||
mLogger.log(this.debugMode, "MissionCardComp", `ensureHeroInfoPanel: updated panel for eid ${eid} at node_index ${expectedNodeIndex}`);
|
||||
}
|
||||
|
||||
private refreshHeroInfoPanels() {
|
||||
@@ -932,7 +944,7 @@ export class MissionCardComp extends CCComp {
|
||||
return;
|
||||
}
|
||||
if (!item.comp.isModelAlive()) {
|
||||
if (item.node.isValid) item.node.destroy();
|
||||
if (item.node.isValid) item.node.active = false;
|
||||
removeKeys.push(eid);
|
||||
return;
|
||||
}
|
||||
@@ -941,7 +953,6 @@ export class MissionCardComp extends CCComp {
|
||||
for (let i = 0; i < removeKeys.length; i++) {
|
||||
this.heroInfoItems.delete(removeKeys[i]);
|
||||
}
|
||||
this.relayoutHeroInfoPanels();
|
||||
this.updateHeroNumUI(false, false);
|
||||
}
|
||||
|
||||
@@ -954,54 +965,24 @@ export class MissionCardComp extends CCComp {
|
||||
item.comp.setBattlePhase(this.isBattlePhase);
|
||||
}
|
||||
|
||||
private relayoutHeroInfoPanels() {
|
||||
const sortedItems = [...this.heroInfoItems.values()].sort((a, b) => {
|
||||
const aEnt = (a.model as any)?.ent as ecs.Entity | undefined;
|
||||
const bEnt = (b.model as any)?.ent as ecs.Entity | undefined;
|
||||
const aView = aEnt?.get(HeroViewComp);
|
||||
const bView = bEnt?.get(HeroViewComp);
|
||||
const aMove = aEnt?.get(MoveComp);
|
||||
const bMove = bEnt?.get(MoveComp);
|
||||
// 排序逻辑反转:适应 cc.Layout 的节点渲染顺序(先渲染/index小的在左边)
|
||||
// 1. x 坐标越小(越靠后排)的,index 应该越小
|
||||
const aFrontScore = aView?.node?.position?.x ?? -999999;
|
||||
const bFrontScore = bView?.node?.position?.x ?? -999999;
|
||||
if (aFrontScore !== bFrontScore) return aFrontScore - bFrontScore;
|
||||
|
||||
const aSpawnOrder = aMove?.spawnOrder ?? 0;
|
||||
const bSpawnOrder = bMove?.spawnOrder ?? 0;
|
||||
if (aSpawnOrder !== bSpawnOrder) return aSpawnOrder - bSpawnOrder;
|
||||
|
||||
const aEid = aEnt?.eid ?? 0;
|
||||
const bEid = bEnt?.eid ?? 0;
|
||||
return aEid - bEid;
|
||||
});
|
||||
|
||||
for (let index = 0; index < sortedItems.length; index++) {
|
||||
const item = sortedItems[index];
|
||||
if (!item.node || !item.node.isValid) continue;
|
||||
|
||||
// 既然使用了 cc.Layout 进行自动排版,我们只需设置渲染顺序
|
||||
// Layout 会自动根据 siblingIndex 对所有子节点重新排位
|
||||
item.node.setSiblingIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
private clearHeroInfoPanels() {
|
||||
if (this.heroInfoItems) {
|
||||
this.heroInfoItems.forEach(item => {
|
||||
if (item && item.node && item.node.isValid) {
|
||||
item.node.destroy();
|
||||
}
|
||||
});
|
||||
this.heroInfoItems.clear();
|
||||
}
|
||||
if (this.hero_info_node && this.hero_info_node.isValid) {
|
||||
for (let i = this.hero_info_node.children.length - 1; i >= 0; i--) {
|
||||
const child = this.hero_info_node.children[i];
|
||||
if (child && child.isValid) child.destroy();
|
||||
}
|
||||
if (this.cachedHInfoComps) {
|
||||
this.cachedHInfoComps.forEach(comp => {
|
||||
if (comp && comp.node && comp.node.isValid) {
|
||||
comp.node.active = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
// 不再销毁子节点,因为它们是预先放置的
|
||||
// if (this.hero_info_node && this.hero_info_node.isValid) {
|
||||
// for (let i = this.hero_info_node.children.length - 1; i >= 0; i--) {
|
||||
// const child = this.hero_info_node.children[i];
|
||||
// if (child && child.isValid) child.destroy();
|
||||
// }
|
||||
// }
|
||||
this.heroInfoSyncTimer = 0;
|
||||
this.syncMissionHeroData(0);
|
||||
this.updateHeroNumUI(false, false);
|
||||
|
||||
Reference in New Issue
Block a user