refactor(map/hero): 重构英雄位置管理逻辑,移除lane相关字段
重构了英雄分路排位的旧实现,改用硬编码的点位数组管理英雄站位,移除了HeroAttrsComp中的lane和lane_index字段,简化了英雄位置分配、UI面板绑定的逻辑,提升代码可维护性。
This commit is contained in:
@@ -64,8 +64,6 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
minSkillDistance: number = 0; // 最近技能攻击距离(缓存,不受MP影响,用于停止位置判断)
|
||||
|
||||
// ==================== 阵型位置 ====================
|
||||
lane: number = -1; // 所在分路:0上路, 1中路, 2下路
|
||||
lane_index: number = -1; // 所在路中的排位:0前排, 1后排
|
||||
|
||||
// ==================== 标记状态 ====================
|
||||
is_dead: boolean = false;
|
||||
@@ -312,8 +310,6 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
this.maxSkillDistance = 0;
|
||||
this.minSkillDistance = 0;
|
||||
|
||||
this.lane = -1;
|
||||
this.lane_index = -1;
|
||||
|
||||
this.is_dead = false;
|
||||
this.is_count_dead = false;
|
||||
|
||||
@@ -46,6 +46,8 @@ interface MoveFacConfig {
|
||||
retreatBackX: number;
|
||||
}
|
||||
|
||||
import { MissionHeroCompComp } from "../map/MissionHeroComp";
|
||||
|
||||
@ecs.register('MoveSystem')
|
||||
export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
||||
private readonly heroFrontAnchorX = -200;
|
||||
@@ -249,20 +251,12 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
|
||||
const slotIndex = Math.max(0, allAllies.findIndex(entity => entity === self));
|
||||
|
||||
const lanePriority = [1, 0, 2]; // 中路优先,其次上路,最后下路
|
||||
const laneOffsets = [100, 0, -100];
|
||||
// 优先中前(1) -> 上前(0) -> 下前(2) -> 中后(4) -> 上后(3) -> 下后(5)
|
||||
const slotPriority = [1, 0, 2, 4, 3, 5];
|
||||
const posIndex = slotPriority[slotIndex % 6];
|
||||
const pos = MissionHeroCompComp.HERO_POSITIONS[posIndex];
|
||||
|
||||
const col = Math.floor(slotIndex / 3);
|
||||
const laneIdx = lanePriority[slotIndex % 3];
|
||||
|
||||
// 动态更新英雄位置数据,为战斗面板排序提供依据
|
||||
model.lane = laneIdx;
|
||||
model.lane_index = col;
|
||||
|
||||
const targetY = BoxSet.GAME_LINE + laneOffsets[laneIdx];
|
||||
const targetX = this.heroFrontAnchorX - col * this.heroAllySpacingX;
|
||||
|
||||
return { targetX, targetY };
|
||||
return { targetX: pos.x, targetY: pos.y };
|
||||
}
|
||||
|
||||
private moveToSlot(view: HeroViewComp, move: MoveComp, model: HeroAttrsComp, targetX: number) {
|
||||
|
||||
@@ -32,6 +32,9 @@ import { GameEvent } from "../common/config/GameEvent";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { UIID } from "../common/config/GameUIConfig";
|
||||
import { mLogger } from "../common/Logger";
|
||||
import { MissionHeroCompComp } from "./MissionHeroComp";
|
||||
import { MoveComp } from "../hero/MoveComp";
|
||||
import { FacSet } from "../common/config/GameSet";
|
||||
|
||||
const {property, ccclass } = _decorator;
|
||||
|
||||
@@ -98,6 +101,44 @@ export class HInfoComp extends CCComp {
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 node_index 获取对应的硬编码位置,并查找该位置的英雄
|
||||
*/
|
||||
refreshByNodeIndex() {
|
||||
if (this.node_index < 1 || this.node_index > 6) return;
|
||||
const targetPos = MissionHeroCompComp.HERO_POSITIONS[this.node_index - 1];
|
||||
|
||||
let foundModel: HeroAttrsComp | null = null;
|
||||
let foundEid: number = 0;
|
||||
|
||||
// 遍历所有英雄,查找 targetX 和 targetY 匹配该位置的英雄
|
||||
ecs.query(ecs.allOf(HeroAttrsComp, MoveComp)).forEach((entity: ecs.Entity) => {
|
||||
const model = entity.get(HeroAttrsComp);
|
||||
const move = entity.get(MoveComp);
|
||||
if (model && move && !model.is_dead && model.fac === FacSet.HERO) {
|
||||
if (Math.abs(move.targetX - targetPos.x) < 2 && Math.abs(move.baseY - targetPos.y) < 2) {
|
||||
foundModel = model;
|
||||
foundEid = entity.eid;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (foundModel) {
|
||||
if (this.eid !== foundEid) {
|
||||
this.bindData(foundEid, foundModel);
|
||||
if (!this.node.active) this.node.active = true;
|
||||
} else {
|
||||
this.refresh();
|
||||
}
|
||||
} else {
|
||||
if (this.eid !== 0) {
|
||||
this.eid = 0;
|
||||
this.model = null;
|
||||
if (this.node.active) this.node.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前是否处于战斗阶段,控制出售按钮显示/隐藏
|
||||
* @param isBattlePhase 是否处于战斗阶段
|
||||
|
||||
@@ -141,15 +141,6 @@ export class MissionCardComp extends CCComp {
|
||||
private cardsHideScale: Vec3 = new Vec3(0, 0, 1);
|
||||
/** 卡牌原始定位点 */
|
||||
private cardsPos = [-260,-75,108,260]
|
||||
/**
|
||||
* 英雄信息面板映射:EID → { node, model, comp }
|
||||
* 用于追踪每个出战英雄的面板实例和数据引用
|
||||
*/
|
||||
private heroInfoItems: Map<number, {
|
||||
node: Node,
|
||||
model: HeroAttrsComp,
|
||||
comp: HInfoComp
|
||||
}> = new Map();
|
||||
/** 缓存预先放置的 6 个 HInfoComp */
|
||||
private cachedHInfoComps: Map<number, HInfoComp> = new Map();
|
||||
// ======================== 生命周期 ========================
|
||||
@@ -226,11 +217,6 @@ export class MissionCardComp extends CCComp {
|
||||
missionData.hero_extend_max_num = FightSet.HERO_MAX_NUM + 1;
|
||||
}
|
||||
|
||||
// 确保 Map 被正确初始化
|
||||
if (!this.heroInfoItems) {
|
||||
this.heroInfoItems = new Map();
|
||||
}
|
||||
|
||||
// 确保卡牌组件列表已被正确缓存
|
||||
if (!this.cardComps || this.cardComps.length === 0) {
|
||||
this.cacheCardComps();
|
||||
@@ -276,7 +262,13 @@ export class MissionCardComp extends CCComp {
|
||||
this.heroInfoSyncTimer += dt;
|
||||
if (this.heroInfoSyncTimer < 0.15) return;
|
||||
this.heroInfoSyncTimer = 0;
|
||||
this.refreshHeroInfoPanels();
|
||||
|
||||
// 遍历所有预设的 HInfoComp,让其根据 node_index 自己刷新
|
||||
this.cachedHInfoComps.forEach(comp => {
|
||||
if (comp && comp.isValid) {
|
||||
comp.refreshByNodeIndex();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -422,14 +414,12 @@ export class MissionCardComp extends CCComp {
|
||||
|
||||
if (!eid || !model) return;
|
||||
const before = this.getAliveHeroCount();
|
||||
this.ensureHeroInfoPanel(eid, model);
|
||||
const after = this.getAliveHeroCount();
|
||||
this.updateHeroNumUI(true, after > before);
|
||||
}
|
||||
|
||||
/** 英雄死亡事件回调:刷新面板列表并更新英雄数量 UI */
|
||||
private onHeroDead() {
|
||||
this.refreshHeroInfoPanels();
|
||||
this.updateHeroNumUI(true, false);
|
||||
}
|
||||
|
||||
@@ -663,9 +653,9 @@ export class MissionCardComp extends CCComp {
|
||||
Tween.stopAllByTarget(this.cards_node);
|
||||
this.cards_node.setScale(this.cardsShowScale);
|
||||
|
||||
this.heroInfoItems.forEach(item => {
|
||||
if (item.comp && item.comp.isValid) {
|
||||
item.comp.setBattlePhase(false);
|
||||
this.cachedHInfoComps.forEach(comp => {
|
||||
if (comp && comp.isValid) {
|
||||
comp.setBattlePhase(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -683,9 +673,9 @@ export class MissionCardComp extends CCComp {
|
||||
})
|
||||
.start();
|
||||
|
||||
this.heroInfoItems.forEach(item => {
|
||||
if (item.comp && item.comp.isValid) {
|
||||
item.comp.setBattlePhase(true);
|
||||
this.cachedHInfoComps.forEach(comp => {
|
||||
if (comp && comp.isValid) {
|
||||
comp.setBattlePhase(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -895,132 +885,7 @@ export class MissionCardComp extends CCComp {
|
||||
return Math.floor(cost);
|
||||
}
|
||||
|
||||
private ensureHeroInfoPanel(eid: number, model: HeroAttrsComp) {
|
||||
if (!this.hero_info_node) {
|
||||
mLogger.error(this.debugMode, "MissionCardComp", "ensureHeroInfoPanel: missing hero_info_node");
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (current) {
|
||||
current.model = model;
|
||||
current.comp = comp;
|
||||
current.node = comp.node;
|
||||
comp.node.active = true;
|
||||
comp.bindData(eid, model);
|
||||
this.updateHeroInfoPanel(current);
|
||||
return;
|
||||
}
|
||||
|
||||
comp.node.active = true;
|
||||
const item = {
|
||||
node: comp.node,
|
||||
model,
|
||||
comp
|
||||
};
|
||||
comp.bindData(eid, model);
|
||||
comp.setBattlePhase(this.isBattlePhase);
|
||||
this.heroInfoItems.set(eid, item);
|
||||
this.updateHeroInfoPanel(item);
|
||||
|
||||
mLogger.log(this.debugMode, "MissionCardComp", `ensureHeroInfoPanel: updated panel for eid ${eid} at node_index ${expectedNodeIndex}`);
|
||||
}
|
||||
|
||||
private refreshHeroInfoPanels() {
|
||||
const removeKeys: number[] = [];
|
||||
|
||||
// 1. 先将已死亡的英雄移除,释放占用的节点
|
||||
this.heroInfoItems.forEach((item, eid) => {
|
||||
if (!item.node || !item.node.isValid) {
|
||||
removeKeys.push(eid);
|
||||
return;
|
||||
}
|
||||
// 使用 model.is_dead 增加判断条件,更加准确
|
||||
if (!item.comp.isModelAlive() || item.model.is_dead) {
|
||||
if (item.node.isValid) item.node.active = false;
|
||||
removeKeys.push(eid);
|
||||
return;
|
||||
}
|
||||
});
|
||||
for (let i = 0; i < removeKeys.length; i++) {
|
||||
this.heroInfoItems.delete(removeKeys[i]);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
private updateHeroInfoPanel(item: {
|
||||
node: Node,
|
||||
model: HeroAttrsComp,
|
||||
comp: HInfoComp
|
||||
}) {
|
||||
item.comp.refresh();
|
||||
item.comp.setBattlePhase(this.isBattlePhase);
|
||||
}
|
||||
|
||||
private clearHeroInfoPanels() {
|
||||
if (this.heroInfoItems) {
|
||||
this.heroInfoItems.clear();
|
||||
}
|
||||
if (this.cachedHInfoComps) {
|
||||
this.cachedHInfoComps.forEach(comp => {
|
||||
if (comp && comp.node && comp.node.isValid) {
|
||||
@@ -1028,13 +893,6 @@ export class MissionCardComp extends CCComp {
|
||||
}
|
||||
});
|
||||
}
|
||||
// 不再销毁子节点,因为它们是预先放置的
|
||||
// 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);
|
||||
@@ -1066,11 +924,11 @@ export class MissionCardComp extends CCComp {
|
||||
|
||||
private getAliveHeroCount(): number {
|
||||
let count = 0;
|
||||
this.heroInfoItems.forEach(item => {
|
||||
if (!item?.node || !item.node.isValid) return;
|
||||
if (!item.comp?.isModelAlive()) return;
|
||||
if (item.model?.is_dead) return;
|
||||
count += 1;
|
||||
ecs.query(ecs.allOf(HeroAttrsComp)).forEach((entity: ecs.Entity) => {
|
||||
const model = entity.get(HeroAttrsComp);
|
||||
if (model && model.fac === FacSet.HERO && !model.is_dead) {
|
||||
count++;
|
||||
}
|
||||
});
|
||||
return count;
|
||||
}
|
||||
@@ -1218,7 +1076,6 @@ export class MissionCardComp extends CCComp {
|
||||
// this.resetButtonScale(this.cards_up);
|
||||
|
||||
// 关键:在 reset/销毁 时将 Map 置空,彻底切断引用
|
||||
this.heroInfoItems = null as any;
|
||||
this.cardComps = [] as any;
|
||||
|
||||
if (this.node && this.node.isValid) {
|
||||
|
||||
@@ -39,6 +39,7 @@ import { FacSet, FightSet, BoxSet } from "../common/config/GameSet";
|
||||
import { oneCom } from "../skill/oncend";
|
||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||
import { FieldSkillSet, FieldSkillType } from "../common/config/SkillSet";
|
||||
import { MoveComp } from "../hero/MoveComp";
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
/**
|
||||
@@ -52,18 +53,18 @@ const { ccclass } = _decorator;
|
||||
export class MissionHeroCompComp extends CCComp {
|
||||
// ======================== 常量 ========================
|
||||
|
||||
/** 硬编码的6个英雄占位点 */
|
||||
public static readonly HERO_POSITIONS: Vec3[] = [
|
||||
v3(-200, BoxSet.GAME_LINE + 100, 0), // index 0 (node_index 1): Top Front
|
||||
v3(-200, BoxSet.GAME_LINE, 0), // index 1 (node_index 2): Mid Front
|
||||
v3(-200, BoxSet.GAME_LINE - 100, 0), // index 2 (node_index 3): Bot Front
|
||||
v3(-300, BoxSet.GAME_LINE + 100, 0), // index 3 (node_index 4): Top Back
|
||||
v3(-300, BoxSet.GAME_LINE, 0), // index 4 (node_index 5): Mid Back
|
||||
v3(-300, BoxSet.GAME_LINE - 100, 0), // index 5 (node_index 6): Bot Back
|
||||
];
|
||||
|
||||
/** 英雄出生时的掉落高度(从空中落到地面的像素差) */
|
||||
private static readonly HERO_DROP_HEIGHT = 260
|
||||
/** 近战英雄起始出生 X 坐标 */
|
||||
private static readonly HERO_SPAWN_START_MELEE_X = -320
|
||||
/** 远程(含中程)英雄起始出生 X 坐标 */
|
||||
private static readonly HERO_SPAWN_START_RANGED_X = -320
|
||||
/** 三路高度偏移(上路, 中路, 下路) */
|
||||
private static readonly HERO_LANE_Y_OFFSETS = [ BoxSet.GAME_LINE+90, BoxSet.GAME_LINE, BoxSet.GAME_LINE-90]
|
||||
/** 每路前排容量 */
|
||||
private static readonly HERO_LANE_CAP = 2
|
||||
/** 同路内 X 间距 */
|
||||
private static readonly HERO_GAP_X = 100
|
||||
|
||||
// ======================== 运行时属性 ========================
|
||||
|
||||
@@ -131,10 +132,7 @@ export class MissionHeroCompComp extends CCComp {
|
||||
if (model && view) {
|
||||
if (model.is_dead) {
|
||||
view.alive();
|
||||
const { lane, indexInLane } = this.pickLaneForHero(model.hero_uuid, [hero.eid]);
|
||||
model.lane = lane;
|
||||
model.lane_index = indexInLane;
|
||||
const landingPos = this.resolveHeroLandingPos(model.hero_uuid, lane, indexInLane);
|
||||
const landingPos = this.pickPositionForHero([hero.eid]);
|
||||
// 不再直接设置位置,而是播放下落入场动画
|
||||
// 计算出出生点(空中)
|
||||
const spawnPos: Vec3 = v3(landingPos.x, landingPos.y + MissionHeroCompComp.HERO_DROP_HEIGHT, 0);
|
||||
@@ -170,43 +168,39 @@ export class MissionHeroCompComp extends CCComp {
|
||||
// ======================== 英雄生成 ========================
|
||||
|
||||
/**
|
||||
* 动态分配英雄上场的路和排位(优先中路 -> 上路 -> 下路)
|
||||
* 标记英雄的6个登录点
|
||||
* @param uuid 英雄 UUID
|
||||
* 动态分配英雄上场的位置
|
||||
* @param excludeEids 排除计算的实体ID数组(避免复活或合成时把自己算成占据的位置)
|
||||
*/
|
||||
private pickLaneForHero(uuid: number, excludeEids: number[] = []): { lane: number; indexInLane: number } {
|
||||
private pickPositionForHero(excludeEids: number[] = []): Vec3 {
|
||||
const heroes = this.getAllHeroes().filter(h => {
|
||||
const m = h.get(HeroAttrsComp);
|
||||
return m && !m.is_dead && !excludeEids.includes(h.eid);
|
||||
});
|
||||
|
||||
// 记录6个位置点的占用情况 [lane][indexInLane]
|
||||
const occupied = [
|
||||
[false, false], // 上路 0
|
||||
[false, false], // 中路 1
|
||||
[false, false] // 下路 2
|
||||
];
|
||||
|
||||
const occupied = new Set<number>();
|
||||
for (const h of heroes) {
|
||||
const m = h.get(HeroAttrsComp);
|
||||
if (m && m.lane >= 0 && m.lane <= 2 && m.lane_index >= 0 && m.lane_index <= 1) {
|
||||
occupied[m.lane][m.lane_index] = true;
|
||||
const move = h.get(MoveComp); // MoveComp 记录了英雄当前的目标位置
|
||||
if (move) {
|
||||
for (let i = 0; i < MissionHeroCompComp.HERO_POSITIONS.length; i++) {
|
||||
const pos = MissionHeroCompComp.HERO_POSITIONS[i];
|
||||
if (Math.abs(move.targetX - pos.x) < 2 && Math.abs(move.baseY - pos.y) < 2) {
|
||||
occupied.add(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 优先中路(1) -> 上路(0) -> 下路(2)
|
||||
const priority = [1, 0, 2];
|
||||
for (let indexInLane = 0; indexInLane < MissionHeroCompComp.HERO_LANE_CAP; indexInLane++) {
|
||||
for (const lane of priority) {
|
||||
if (!occupied[lane][indexInLane]) {
|
||||
return { lane, indexInLane };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 溢出:仍放中路,沿 X 继续排
|
||||
return { lane: 1, indexInLane: 2 };
|
||||
// 优先中前(1) -> 上前(0) -> 下前(2) -> 中后(4) -> 上后(3) -> 下后(5)
|
||||
const slotPriority = [1, 0, 2, 4, 3, 5];
|
||||
for (const idx of slotPriority) {
|
||||
if (!occupied.has(idx)) {
|
||||
return MissionHeroCompComp.HERO_POSITIONS[idx];
|
||||
}
|
||||
}
|
||||
|
||||
// 溢出:默认中前
|
||||
return MissionHeroCompComp.HERO_POSITIONS[1];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,16 +217,13 @@ export class MissionHeroCompComp extends CCComp {
|
||||
console.log("addHero uuid:",uuid)
|
||||
let hero = ecs.getEntity<Hero>(Hero);
|
||||
let scale = 1
|
||||
const { lane, indexInLane } = this.pickLaneForHero(uuid);
|
||||
const landingPos = this.resolveHeroLandingPos(uuid, lane, indexInLane);
|
||||
const landingPos = this.pickPositionForHero();
|
||||
let spawnPos:Vec3 = v3(landingPos.x, landingPos.y + MissionHeroCompComp.HERO_DROP_HEIGHT, 0);
|
||||
hero.load(spawnPos,scale,uuid,landingPos.y,hero_lv,pool_lv);
|
||||
|
||||
// 召唤完成后,派发事件以更新英雄面板
|
||||
const model = hero.get(HeroAttrsComp);
|
||||
if (model) {
|
||||
model.lane = lane;
|
||||
model.lane_index = indexInLane;
|
||||
oops.message.dispatchEvent(GameEvent.MasterCalled, {
|
||||
eid: hero.eid,
|
||||
model: model
|
||||
@@ -242,33 +233,7 @@ export class MissionHeroCompComp extends CCComp {
|
||||
return hero;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算英雄落点位置。
|
||||
* Y 坐标来自 HeroPos 配置,X 坐标根据英雄类型(近战/远程)决定。
|
||||
*
|
||||
* @param uuid 英雄 UUID
|
||||
* @param lane 分配到的路 (0: 上, 1: 中, 2: 下)
|
||||
* @param indexInLane 该路排位
|
||||
* @returns 落点 Vec3
|
||||
*/
|
||||
private resolveHeroLandingPos(uuid: number, lane: number, indexInLane: number): Vec3 {
|
||||
const hero_pos = 0;
|
||||
const baseY = HeroPos[hero_pos].pos.y + MissionHeroCompComp.HERO_LANE_Y_OFFSETS[lane];
|
||||
const startX = this.resolveSpawnStartX(uuid);
|
||||
return v3(startX + indexInLane * MissionHeroCompComp.HERO_GAP_X, baseY, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据英雄类型决定出生 X 坐标。
|
||||
* @param uuid 英雄 UUID
|
||||
* @returns 近战 or 远程的起始 X
|
||||
*/
|
||||
private resolveSpawnStartX(uuid: number): number {
|
||||
const heroType = HeroInfo[uuid]?.type;
|
||||
return heroType === HType.Melee
|
||||
? MissionHeroCompComp.HERO_SPAWN_START_MELEE_X
|
||||
: MissionHeroCompComp.HERO_SPAWN_START_RANGED_X;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成合成后的高级英雄,并覆盖为聚合后的属性。
|
||||
@@ -278,33 +243,21 @@ export class MissionHeroCompComp extends CCComp {
|
||||
* @param pool_lv 卡池等级
|
||||
* @param ap 聚合后攻击力
|
||||
* @param hp_max 聚合后最大生命值
|
||||
* @param targetLane 指定生成路
|
||||
* @param targetIndex 指定该路排位
|
||||
* @param targetPos 指定生成位置
|
||||
* @returns 实际生成的英雄等级
|
||||
*/
|
||||
private addMergedHero(uuid:number, hero_lv:number, pool_lv:number, ap:number, hp_max:number, targetLane?: number, targetIndex?: number): number {
|
||||
private addMergedHero(uuid:number, hero_lv:number, pool_lv:number, ap:number, hp_max:number, targetPos?: Vec3): number {
|
||||
console.log("addMergedHero uuid:",uuid)
|
||||
let hero = ecs.getEntity<Hero>(Hero);
|
||||
let scale = 1
|
||||
|
||||
// 如果未指定路,则按普通添加英雄处理
|
||||
let lane = targetLane;
|
||||
let indexInLane = targetIndex;
|
||||
if (lane === undefined || indexInLane === undefined) {
|
||||
const res = this.pickLaneForHero(uuid);
|
||||
lane = res.lane;
|
||||
indexInLane = res.indexInLane;
|
||||
}
|
||||
|
||||
const landingPos = this.resolveHeroLandingPos(uuid, lane, indexInLane);
|
||||
const landingPos = targetPos || this.pickPositionForHero();
|
||||
let spawnPos:Vec3 = v3(landingPos.x, landingPos.y + MissionHeroCompComp.HERO_DROP_HEIGHT, 0);
|
||||
hero.load(spawnPos,scale,uuid,landingPos.y,hero_lv,pool_lv);
|
||||
|
||||
// 召唤完成后,派发事件以更新英雄面板
|
||||
const model = hero.get(HeroAttrsComp);
|
||||
if (model) {
|
||||
model.lane = lane;
|
||||
model.lane_index = indexInLane;
|
||||
model.ap = Math.max(0, ap);
|
||||
model.hp_max = Math.max(1, hp_max);
|
||||
model.hp = model.hp_max;
|
||||
@@ -540,14 +493,13 @@ export class MissionHeroCompComp extends CCComp {
|
||||
}
|
||||
|
||||
// 计算目标出生点(提前排除素材英雄所占的位置)
|
||||
const { lane, indexInLane } = this.pickLaneForHero(uuid, mergeEids);
|
||||
const landingPos = this.resolveHeroLandingPos(uuid, lane, indexInLane);
|
||||
const landingPos = this.pickPositionForHero(mergeEids);
|
||||
const spawnPos:Vec3 = v3(landingPos.x, landingPos.y + MissionHeroCompComp.HERO_DROP_HEIGHT, 0);
|
||||
|
||||
// 汇聚 → 特效 → 生成
|
||||
await this.mergeDestroyAtBirth(mergeHeroes, spawnPos);
|
||||
await this.playMergeBoomFx(spawnPos);
|
||||
return this.addMergedHero(uuid, Math.min(this.merge_max_lv, hero_lv + 1), pool_lv, sumAp, sumHpMax, lane, indexInLane);
|
||||
return this.addMergedHero(uuid, Math.min(this.merge_max_lv, hero_lv + 1), pool_lv, sumAp, sumHpMax, landingPos);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user