Merge branch 'card' of git.eoxnet.com:pan/pixelheros into card

This commit is contained in:
walkpan
2026-05-13 18:52:42 +08:00
18 changed files with 5784 additions and 3496 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -110,7 +110,7 @@
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 45, "x": 0,
"y": 0, "y": 0,
"z": 0 "z": 0
}, },
@@ -151,8 +151,8 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 160, "width": 200,
"height": 160 "height": 200
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
@@ -294,8 +294,8 @@
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 45, "x": 0,
"y": 17.631, "y": 11.301,
"z": 0 "z": 0
}, },
"_lrot": { "_lrot": {
@@ -307,8 +307,8 @@
}, },
"_lscale": { "_lscale": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": -0.8, "x": -1,
"y": 0.8, "y": 1,
"z": 1 "z": 1
}, },
"_mobility": 0, "_mobility": 0,
@@ -509,7 +509,7 @@
"_top": 0, "_top": 0,
"_bottom": 0, "_bottom": 0,
"_horizontalCenter": 0, "_horizontalCenter": 0,
"_verticalCenter": 17.631, "_verticalCenter": 11.301,
"_isAbsLeft": true, "_isAbsLeft": true,
"_isAbsRight": true, "_isAbsRight": true,
"_isAbsTop": true, "_isAbsTop": true,
@@ -572,7 +572,7 @@
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 103.653, "x": 72.111,
"y": 0, "y": 0,
"z": 0 "z": 0
}, },
@@ -772,8 +772,8 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 60, "width": 80,
"height": 170 "height": 210
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
@@ -991,8 +991,8 @@
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 45, "x": 0,
"y": -8.595, "y": -12.461,
"z": 0 "z": 0
}, },
"_lrot": { "_lrot": {
@@ -1085,8 +1085,8 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 90, "width": 105,
"height": 20 "height": 25
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
@@ -1163,8 +1163,8 @@
"_target": null, "_target": null,
"_left": 0, "_left": 0,
"_right": 0, "_right": 0,
"_top": 0, "_top": -2.5,
"_bottom": 0, "_bottom": -2.5,
"_horizontalCenter": 0, "_horizontalCenter": 0,
"_verticalCenter": 0, "_verticalCenter": 0,
"_isAbsLeft": true, "_isAbsLeft": true,
@@ -1435,8 +1435,8 @@
"_string": "99999", "_string": "99999",
"_horizontalAlign": 1, "_horizontalAlign": 1,
"_verticalAlign": 1, "_verticalAlign": 1,
"_actualFontSize": 18, "_actualFontSize": 20,
"_fontSize": 18, "_fontSize": 20,
"_fontFamily": "Arial", "_fontFamily": "Arial",
"_lineHeight": 20, "_lineHeight": 20,
"_overflow": 2, "_overflow": 2,
@@ -1505,7 +1505,7 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 90, "width": 105,
"height": 20 "height": 20
}, },
"_anchorPoint": { "_anchorPoint": {
@@ -1649,8 +1649,8 @@
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 45, "x": 0,
"y": -26.278, "y": -35.14,
"z": 0 "z": 0
}, },
"_lrot": { "_lrot": {
@@ -1743,8 +1743,8 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 90, "width": 105,
"height": 20 "height": 25
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
@@ -1821,8 +1821,8 @@
"_target": null, "_target": null,
"_left": 0, "_left": 0,
"_right": 0, "_right": 0,
"_top": 0, "_top": -2.5,
"_bottom": 0, "_bottom": -2.5,
"_horizontalCenter": 0, "_horizontalCenter": 0,
"_verticalCenter": 0, "_verticalCenter": 0,
"_isAbsLeft": true, "_isAbsLeft": true,
@@ -2093,8 +2093,8 @@
"_string": "99999", "_string": "99999",
"_horizontalAlign": 1, "_horizontalAlign": 1,
"_verticalAlign": 1, "_verticalAlign": 1,
"_actualFontSize": 18, "_actualFontSize": 20,
"_fontSize": 18, "_fontSize": 20,
"_fontFamily": "Arial", "_fontFamily": "Arial",
"_lineHeight": 20, "_lineHeight": 20,
"_overflow": 2, "_overflow": 2,
@@ -2163,7 +2163,7 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 90, "width": 105,
"height": 20 "height": 20
}, },
"_anchorPoint": { "_anchorPoint": {
@@ -2310,7 +2310,7 @@
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 45, "x": 0,
"y": 0, "y": 0,
"z": 0 "z": 0
}, },
@@ -2582,8 +2582,8 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 180, "width": 220,
"height": 180 "height": 220
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
@@ -3241,8 +3241,8 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 90, "width": 110,
"height": 90 "height": 110
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
@@ -5242,8 +5242,8 @@
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 45, "x": 0,
"y": 40.66599999999994, "y": 46.513,
"z": 0 "z": 0
}, },
"_lrot": { "_lrot": {
@@ -5392,12 +5392,12 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 90, "width": 110,
"height": 90 "height": 110
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
"x": 0, "x": 0.5,
"y": 0.5 "y": 0.5
}, },
"_id": "" "_id": ""

File diff suppressed because it is too large Load Diff

View File

@@ -47,10 +47,13 @@
}, },
{ {
"__id__": 187 "__id__": 187
},
{
"__id__": 189
} }
], ],
"_prefab": { "_prefab": {
"__id__": 189 "__id__": 191
}, },
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
@@ -3832,6 +3835,8 @@
"__id__": 0 "__id__": 0
}, },
"fileId": "60zyAJG75FD4lr3BUqk8h+", "fileId": "60zyAJG75FD4lr3BUqk8h+",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null "nestedPrefabInstanceRoots": null
}, },
{ {
@@ -3966,6 +3971,8 @@
"__id__": 0 "__id__": 0
}, },
"fileId": "5baCaOgaJJj5xGYYZRPLag", "fileId": "5baCaOgaJJj5xGYYZRPLag",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null "nestedPrefabInstanceRoots": null
}, },
{ {
@@ -4320,6 +4327,24 @@
"__type__": "cc.CompPrefabInfo", "__type__": "cc.CompPrefabInfo",
"fileId": "a8f3R/dcVJa4WiCkhL/wGK" "fileId": "a8f3R/dcVJa4WiCkhL/wGK"
}, },
{
"__type__": "cc.BlockInputEvents",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 190
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "06K0yfnYlMPJjdjg9cQ8Rg"
},
{ {
"__type__": "cc.PrefabInfo", "__type__": "cc.PrefabInfo",
"root": { "root": {
@@ -4330,6 +4355,7 @@
}, },
"fileId": "84hrfbDo1AOq3VROGZvWWt", "fileId": "84hrfbDo1AOq3VROGZvWWt",
"instance": null, "instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": [ "nestedPrefabInstanceRoots": [
{ {
"__id__": 151 "__id__": 151

View File

@@ -158,34 +158,34 @@ export const HeroInfo: Record<number, heroInfo> = {
// ========== 法师英雄 ========== // ========== 法师英雄 ==========
5101:{uuid:5101,name:t("hero_name_5101"),path:"hm2", fac:FacSet.HERO,cards_lv:1,lv:1,type:HType.Long,hp:50,ap:60,speed:800,revive:{s_uuid:6501,r_num:1,upr:0.5}, 5101:{uuid:5101,name:t("hero_name_5101"),path:"hm2", fac:FacSet.HERO,cards_lv:1,lv:1,type:HType.Long,hp:150,ap:60,speed:800,revive:{s_uuid:6501,r_num:1,upr:0.5},
skills:{6201:{uuid:6007,lv:1,cd:1,ccd:0}},info:t("hero_info_5101")}, skills:{6201:{uuid:6007,lv:1,cd:1,ccd:0}},info:t("hero_info_5101")},
5102:{uuid:5102,name:t("hero_name_5102"),path:"hm1", fac:FacSet.HERO,cards_lv:2,lv:1,type:HType.Long,hp:30,ap:120,speed:800, 5102:{uuid:5102,name:t("hero_name_5102"),path:"hm1", fac:FacSet.HERO,cards_lv:2,lv:1,type:HType.Long,hp:130,ap:120,speed:800,
skills:{6203:{uuid:6002,lv:1,cd:1,ccd:0}},info:t("hero_info_5102")}, skills:{6203:{uuid:6002,lv:1,cd:1,ccd:0}},info:t("hero_info_5102")},
5103:{uuid:5103,name:t("hero_name_5103"),path:"hm9", fac:FacSet.HERO,cards_lv:3,lv:1,type:HType.Long,hp:45,ap:180,speed:800, 5103:{uuid:5103,name:t("hero_name_5103"),path:"hm9", fac:FacSet.HERO,cards_lv:3,lv:1,type:HType.Long,hp:145,ap:180,speed:800,
skills:{6201:{uuid:6002,lv:1,cd:1,ccd:0}},info:t("hero_info_5103")}, skills:{6201:{uuid:6002,lv:1,cd:1,ccd:0}},info:t("hero_info_5103")},
5104:{uuid:5104,name:t("hero_name_5104"),path:"hm4", fac:FacSet.HERO,cards_lv:4,lv:1,type:HType.Long,hp:60,ap:240,speed:800, 5104:{uuid:5104,name:t("hero_name_5104"),path:"hm4", fac:FacSet.HERO,cards_lv:4,lv:1,type:HType.Long,hp:160,ap:240,speed:800,
skills:{6201:{uuid:66002201,lv:1,cd:1,ccd:0}},info:t("hero_info_5104")}, skills:{6201:{uuid:66002201,lv:1,cd:1,ccd:0}},info:t("hero_info_5104")},
5105:{uuid:5105,name:t("hero_name_5105"),path:"hm3", fac:FacSet.HERO,cards_lv:5,lv:1,type:HType.Long,hp:75,ap:300,speed:800, 5105:{uuid:5105,name:t("hero_name_5105"),path:"hm3", fac:FacSet.HERO,cards_lv:5,lv:1,type:HType.Long,hp:175,ap:300,speed:800,
skills:{6203:{uuid:6002,lv:1,cd:1,ccd:0}},info:t("hero_info_5105") }, skills:{6203:{uuid:6002,lv:1,cd:1,ccd:0}},info:t("hero_info_5105") },
// ========== 远程英雄 ========== // ========== 远程英雄 ==========
5201:{uuid:5201,name:t("hero_name_5201"),path:"ha1", fac:FacSet.HERO,cards_lv:1,lv:1,type:HType.Long,hp:15,ap:60,speed:800, 5201:{uuid:5201,name:t("hero_name_5201"),path:"ha1", fac:FacSet.HERO,cards_lv:1,lv:1,type:HType.Long,hp:115,ap:60,speed:800,
skills:{6101:{uuid:6005,lv:1,cd:0.9,ccd:0}},info:t("hero_info_5201")}, skills:{6101:{uuid:6005,lv:1,cd:0.9,ccd:0}},info:t("hero_info_5201")},
5202:{uuid:5202,name:t("hero_name_5202"),path:"ha2", fac:FacSet.HERO,cards_lv:3,lv:1,type:HType.Long,hp:45,ap:180,speed:800, 5202:{uuid:5202,name:t("hero_name_5202"),path:"ha2", fac:FacSet.HERO,cards_lv:3,lv:1,type:HType.Long,hp:145,ap:180,speed:800,
skills:{6011:{uuid:6005,lv:1,cd:0.9,ccd:0}},info:t("hero_info_5202")}, skills:{6011:{uuid:6005,lv:1,cd:0.9,ccd:0}},info:t("hero_info_5202")},
5203:{uuid:5203,name:t("hero_name_5203"),path:"ha3", fac:FacSet.HERO,cards_lv:3,lv:1,type:HType.Long,hp:45,ap:180,speed:800, 5203:{uuid:5203,name:t("hero_name_5203"),path:"ha3", fac:FacSet.HERO,cards_lv:3,lv:1,type:HType.Long,hp:145,ap:180,speed:800,
skills:{6011:{uuid:6005,lv:1,cd:0.9,ccd:0}},info:t("hero_info_5203")}, skills:{6011:{uuid:6005,lv:1,cd:0.9,ccd:0}},info:t("hero_info_5203")},
// ========== 辅助英雄 ========== // ========== 辅助英雄 ==========
5301:{uuid:5301,name:t("hero_name_5301"),path:"hh1", fac:FacSet.HERO,cards_lv:1,lv:1,type:HType.Long,hp:15,ap:20,speed:800,atking:[{s_uuid:6302,t_num:2}], 5301:{uuid:5301,name:t("hero_name_5301"),path:"hh1", fac:FacSet.HERO,cards_lv:1,lv:1,type:HType.Long,hp:115,ap:50,speed:800,atking:[{s_uuid:6302,t_num:2}],
skills:{6202:{uuid:6004,lv:1,cd:1.2,ccd:0}},info:t("hero_info_5301") }, skills:{6202:{uuid:6004,lv:1,cd:1.2,ccd:0}},info:t("hero_info_5301") },
5302:{uuid:5302,name:t("hero_name_5302"),path:"hz1", fac:FacSet.HERO,cards_lv:2,lv:1,type:HType.Long,hp:30,ap:40,speed:800,atking:[{s_uuid:6304,t_num:2}], 5302:{uuid:5302,name:t("hero_name_5302"),path:"hz1", fac:FacSet.HERO,cards_lv:2,lv:1,type:HType.Long,hp:130,ap:50,speed:800,atking:[{s_uuid:6304,t_num:2}],
skills:{6202:{uuid:6004,lv:1,cd:1.2,ccd:0}},info:t("hero_info_5302")}, skills:{6202:{uuid:6004,lv:1,cd:1.2,ccd:0}},info:t("hero_info_5302")},
5303:{uuid:5303,name:t("hero_name_5303"),path:"hm6", fac:FacSet.HERO,cards_lv:4,lv:1,type:HType.Long,hp:60,ap:80,speed:800, 5303:{uuid:5303,name:t("hero_name_5303"),path:"hm6", fac:FacSet.HERO,cards_lv:4,lv:1,type:HType.Long,hp:160,ap:80,speed:800,
skills:{6202:{uuid:6004,lv:1,cd:1.2,ccd:0}},info:t("hero_info_5303")}, skills:{6202:{uuid:6004,lv:1,cd:1.2,ccd:0}},info:t("hero_info_5303")},
5304:{uuid:5304,name:t("hero_name_5304"),path:"hm7", fac:FacSet.HERO,cards_lv:6,lv:1,type:HType.Long,hp:90,ap:120,speed:800, 5304:{uuid:5304,name:t("hero_name_5304"),path:"hm7", fac:FacSet.HERO,cards_lv:6,lv:1,type:HType.Long,hp:190,ap:120,speed:800,
skills:{6202:{uuid:6004,lv:1,cd:1.2,ccd:0}},info:t("hero_info_5304")}, skills:{6202:{uuid:6004,lv:1,cd:1.2,ccd:0}},info:t("hero_info_5304")},

View File

@@ -157,6 +157,7 @@ export class CardComp extends CCComp {
/** 组件销毁时解绑所有事件,防止残留回调 */ /** 组件销毁时解绑所有事件,防止残留回调 */
onDestroy() { onDestroy() {
super.onDestroy();
this.unbindEvents(); this.unbindEvents();
} }

View File

@@ -60,6 +60,9 @@ export class HInfoComp extends CCComp {
@property(Node) @property(Node)
lv_node=null! lv_node=null!
@property(Number)
node_index=0
/** 绑定的英雄 ECS 实体 ID */ /** 绑定的英雄 ECS 实体 ID */
private eid: number = 0; private eid: number = 0;
/** 绑定的英雄属性数据模型引用 */ /** 绑定的英雄属性数据模型引用 */
@@ -80,6 +83,7 @@ export class HInfoComp extends CCComp {
} }
onDestroy() { onDestroy() {
super.onDestroy();
} }
/** /**

View File

@@ -79,6 +79,7 @@ export class IBoxComp extends CCComp {
/** 解绑点击事件 */ /** 解绑点击事件 */
onDestroy() { onDestroy() {
super.onDestroy();
if (this.node && this.node.isValid) { if (this.node && this.node.isValid) {
this.node.off(NodeEventType.TOUCH_END, this.onTapClose, this); this.node.off(NodeEventType.TOUCH_END, this.onTapClose, this);
} }

View File

@@ -84,6 +84,7 @@ export class MissSkillsComp extends CCComp {
/** 移除事件监听 */ /** 移除事件监听 */
onDestroy() { onDestroy() {
super.onDestroy();
oops.message.off(GameEvent.UseSkillCard, this.onUseSkillCard, this); oops.message.off(GameEvent.UseSkillCard, this.onUseSkillCard, this);
oops.message.off(GameEvent.RemoveSkillBox, this.onRemoveSkillBox, this); oops.message.off(GameEvent.RemoveSkillBox, this.onRemoveSkillBox, this);
} }

View File

@@ -150,6 +150,8 @@ export class MissionCardComp extends CCComp {
model: HeroAttrsComp, model: HeroAttrsComp,
comp: HInfoComp comp: HInfoComp
}> = new Map(); }> = new Map();
/** 缓存预先放置的 6 个 HInfoComp */
private cachedHInfoComps: Map<number, HInfoComp> = new Map();
// ======================== 生命周期 ======================== // ======================== 生命周期 ========================
/** /**
@@ -161,6 +163,7 @@ export class MissionCardComp extends CCComp {
* 5. 触发首次任务开始流程。 * 5. 触发首次任务开始流程。
*/ */
onLoad() { onLoad() {
this.cacheHInfoComps();
this.bindEvents(); this.bindEvents();
this.cacheCardComps(); this.cacheCardComps();
this.layoutCardSlots(); this.layoutCardSlots();
@@ -171,9 +174,23 @@ export class MissionCardComp extends CCComp {
poolLv: this.poolLv 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() { onDestroy() {
super.onDestroy();
if (this.cards_chou && this.cards_chou.isValid) { if (this.cards_chou && this.cards_chou.isValid) {
this.cards_chou.off(NodeEventType.TOUCH_START, this.onDrawTouchStart, this); this.cards_chou.off(NodeEventType.TOUCH_START, this.onDrawTouchStart, this);
this.cards_chou.off(NodeEventType.TOUCH_END, this.onDrawTouchEnd, this); this.cards_chou.off(NodeEventType.TOUCH_END, this.onDrawTouchEnd, this);
@@ -879,68 +896,115 @@ export class MissionCardComp extends CCComp {
} }
private ensureHeroInfoPanel(eid: number, model: HeroAttrsComp) { private ensureHeroInfoPanel(eid: number, model: HeroAttrsComp) {
if (!this.hero_info_node || !this.hero_info_prefab) { if (!this.hero_info_node) {
mLogger.error(this.debugMode, "MissionCardComp", "ensureHeroInfoPanel: missing hero_info_node or hero_info_prefab"); mLogger.error(this.debugMode, "MissionCardComp", "ensureHeroInfoPanel: missing hero_info_node");
return; return;
} }
this.hero_info_node.active = true;
// MoveComp.ts 里的 assignment:
// lanePriority = [1, 0, 2]; // slotIndex 0->中路(1), 1->上路(0), 2->下路(2)
// laneIdx = lanePriority[slotIndex % 3]; // priority: 1(中), 0(上), 2(下)
// model.lane = laneIdx;
//
// 所以当:
// model.lane = 0 (上路), model.lane_index = 0 -> 对应 node_index = 1
// model.lane = 1 (中路), model.lane_index = 0 -> 对应 node_index = 2
// model.lane = 2 (下路), model.lane_index = 0 -> 对应 node_index = 3
const expectedNodeIndex = model.lane_index * 3 + model.lane + 1;
mLogger.log(this.debugMode, "MissionCardComp", `ensureHeroInfoPanel calculation: lane=${model.lane}, lane_index=${model.lane_index} -> expectedNodeIndex=${expectedNodeIndex}`);
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); const current = this.heroInfoItems.get(eid);
if (current) { if (current) {
current.model = model; 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); this.updateHeroInfoPanel(current);
return; return;
} }
mLogger.log(this.debugMode, "MissionCardComp", "ensureHeroInfoPanel: creating new panel for eid", eid); comp.node.active = true;
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;
}
const item = { const item = {
node, node: comp.node,
model, model,
comp comp
}; };
comp.bindData(eid, model); comp.bindData(eid, model);
comp.setBattlePhase(this.isBattlePhase); comp.setBattlePhase(this.isBattlePhase);
this.heroInfoItems.set(eid, item); this.heroInfoItems.set(eid, item);
this.relayoutHeroInfoPanels();
this.updateHeroInfoPanel(item); 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() { private refreshHeroInfoPanels() {
const removeKeys: number[] = []; const removeKeys: number[] = [];
// 1. 先将已死亡的英雄移除,释放占用的节点
this.heroInfoItems.forEach((item, eid) => { this.heroInfoItems.forEach((item, eid) => {
if (!item.node || !item.node.isValid) { if (!item.node || !item.node.isValid) {
removeKeys.push(eid); removeKeys.push(eid);
return; return;
} }
if (!item.comp.isModelAlive()) { // 使用 model.is_dead 增加判断条件,更加准确
if (item.node.isValid) item.node.destroy(); if (!item.comp.isModelAlive() || item.model.is_dead) {
if (item.node.isValid) item.node.active = false;
removeKeys.push(eid); removeKeys.push(eid);
return; return;
} }
this.updateHeroInfoPanel(item);
}); });
for (let i = 0; i < removeKeys.length; i++) { for (let i = 0; i < removeKeys.length; i++) {
this.heroInfoItems.delete(removeKeys[i]); this.heroInfoItems.delete(removeKeys[i]);
} }
this.relayoutHeroInfoPanels();
// 2. 然后再处理所有存活英雄的位置转移和信息刷新
// 如果有多个英雄在同一帧发生位置变动,我们需要统一处理
const needTransfer: Array<{eid: number, expectedNodeIndex: number}> = [];
this.heroInfoItems.forEach((item, eid) => {
// 检查英雄是否改变了位置 (lane 或 lane_index 发生了变化)
const expectedNodeIndex = item.model.lane_index * 3 + item.model.lane + 1;
if (item.comp.node_index !== expectedNodeIndex) {
// 如果位置变了,需要转移到新的节点上
const newComp = this.cachedHInfoComps.get(expectedNodeIndex);
if (newComp) {
needTransfer.push({eid, expectedNodeIndex});
// 将原来的节点释放,以供其他可能换到这个位置的英雄使用
item.node.active = false;
}
} else {
this.updateHeroInfoPanel(item);
}
});
// 执行位置转移
for (const transfer of needTransfer) {
const item = this.heroInfoItems.get(transfer.eid);
if (!item) continue;
const newComp = this.cachedHInfoComps.get(transfer.expectedNodeIndex);
if (newComp) {
// 转移到新节点
item.comp = newComp;
item.node = newComp.node;
item.node.active = true;
item.comp.bindData(transfer.eid, item.model);
item.comp.setBattlePhase(this.isBattlePhase);
this.updateHeroInfoPanel(item);
}
}
this.updateHeroNumUI(false, false); this.updateHeroNumUI(false, false);
} }
@@ -953,54 +1017,24 @@ export class MissionCardComp extends CCComp {
item.comp.setBattlePhase(this.isBattlePhase); 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() { private clearHeroInfoPanels() {
if (this.heroInfoItems) { if (this.heroInfoItems) {
this.heroInfoItems.forEach(item => {
if (item && item.node && item.node.isValid) {
item.node.destroy();
}
});
this.heroInfoItems.clear(); this.heroInfoItems.clear();
} }
if (this.hero_info_node && this.hero_info_node.isValid) { if (this.cachedHInfoComps) {
for (let i = this.hero_info_node.children.length - 1; i >= 0; i--) { this.cachedHInfoComps.forEach(comp => {
const child = this.hero_info_node.children[i]; if (comp && comp.node && comp.node.isValid) {
if (child && child.isValid) child.destroy(); 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.heroInfoSyncTimer = 0;
this.syncMissionHeroData(0); this.syncMissionHeroData(0);
this.updateHeroNumUI(false, false); this.updateHeroNumUI(false, false);

View File

@@ -201,6 +201,7 @@ export class MissionComp extends CCComp {
} }
onDestroy(){ onDestroy(){
super.onDestroy();
if (this.start_btn && this.start_btn.isValid) { if (this.start_btn && this.start_btn.isValid) {
this.start_btn.off(NodeEventType.TOUCH_END, this.onStartFightBtnClick, this); this.start_btn.off(NodeEventType.TOUCH_END, this.onStartFightBtnClick, this);
} }

View File

@@ -101,6 +101,7 @@ export class MissionHeroCompComp extends CCComp {
} }
onDestroy(){ onDestroy(){
super.onDestroy();
// 清理全部监听 // 清理全部监听
oops.message.off(GameEvent.CallHero,this.call_hero,this) oops.message.off(GameEvent.CallHero,this.call_hero,this)
oops.message.off("PhasePrepareStart",this.fight_ready,this) oops.message.off("PhasePrepareStart",this.fight_ready,this)
@@ -196,8 +197,8 @@ export class MissionHeroCompComp extends CCComp {
// 优先中路(1) -> 上路(0) -> 下路(2) // 优先中路(1) -> 上路(0) -> 下路(2)
const priority = [1, 0, 2]; const priority = [1, 0, 2];
for (const lane of priority) { for (let indexInLane = 0; indexInLane < MissionHeroCompComp.HERO_LANE_CAP; indexInLane++) {
for (let indexInLane = 0; indexInLane < MissionHeroCompComp.HERO_LANE_CAP; indexInLane++) { for (const lane of priority) {
if (!occupied[lane][indexInLane]) { if (!occupied[lane][indexInLane]) {
return { lane, indexInLane }; return { lane, indexInLane };
} }

View File

@@ -66,7 +66,7 @@ export class RanksComp extends CCComp {
} }
onDestroy() { onDestroy() {
super.onDestroy();
} }
/** 关闭排行榜弹窗 */ /** 关闭排行榜弹窗 */

View File

@@ -92,6 +92,7 @@ export class SkillBoxComp extends CCComp {
/** 销毁时移除所有事件监听并通知槽位管理器回收 */ /** 销毁时移除所有事件监听并通知槽位管理器回收 */
onDestroy() { onDestroy() {
super.onDestroy();
oops.message.off(GameEvent.FightStart, this.onFightStart, this); oops.message.off(GameEvent.FightStart, this.onFightStart, this);
oops.message.off(GameEvent.MissionEnd, this.onMissionEnd, this); oops.message.off(GameEvent.MissionEnd, this.onMissionEnd, this);
if (this.node && this.node.isValid) { if (this.node && this.node.isValid) {

View File

@@ -113,6 +113,7 @@ export class TalentItemComp extends CCComp {
} }
protected onDestroy(): void { protected onDestroy(): void {
super.onDestroy();
if (this.btn_upgrade && this.btn_upgrade.node && this.btn_upgrade.node.isValid) { if (this.btn_upgrade && this.btn_upgrade.node && this.btn_upgrade.node.isValid) {
this.btn_upgrade.node.off(Button.EventType.CLICK, this.onUpgradeClicked, this); this.btn_upgrade.node.off(Button.EventType.CLICK, this.onUpgradeClicked, this);
} }

View File

@@ -254,6 +254,7 @@ export class TalentsComp extends CCComp {
} }
protected onDestroy(): void { protected onDestroy(): void {
super.onDestroy();
mLogger.log(this.debugMode, 'TalentsComp', "释放界面"); mLogger.log(this.debugMode, 'TalentsComp', "释放界面");
if (this.btn_reset && this.btn_reset.node && this.btn_reset.node.isValid) { if (this.btn_reset && this.btn_reset.node && this.btn_reset.node.isValid) {
this.btn_reset.node.off(Button.EventType.CLICK, this.onResetClicked, this); this.btn_reset.node.off(Button.EventType.CLICK, this.onResetClicked, this);

View File

@@ -598,6 +598,7 @@ export class VictoryComp extends CCComp {
} }
protected onDestroy(): void { protected onDestroy(): void {
super.onDestroy();
mLogger.log(this.debugMode, 'VictoryComp', "释放胜利界面"); mLogger.log(this.debugMode, 'VictoryComp', "释放胜利界面");
} }