refactor(battle): 重构战斗目标查找与位置管理逻辑

新增全局位置网格系统,用于按索引存储敌我单位实体ID:
-  在SingletonModuleComp添加heroGrid与monGrid数组
-  为HeroAttrsComp新增posIndex字段记录位置索引并初始化

优化战斗核心流程:
-  重构MissionHeroComp的位置选择逻辑,拆分方法返回位置索引而非直接坐标,优化位置占用检测
-  重构SCastSystem的目标查找与收集逻辑,改用网格遍历替代全量实体查询,大幅提升性能
-  统一三路单位的查找优先级,简化代码提升可维护性
-  完善Hero与Monster的创建销毁流程,同步更新网格的单位注册与注销信息
This commit is contained in:
pan
2026-06-17 09:45:46 +08:00
parent 06a47842dd
commit b6b2dff986
7 changed files with 144 additions and 142 deletions

View File

@@ -132,11 +132,14 @@ export class MissionHeroComp extends CCComp {
if (model && view) {
if (model.is_dead) {
view.alive();
const landingPos = this.pickPositionForHero([hero.eid]);
const posIndex = this.pickPositionIndexForHero([hero.eid]);
const landingPos = MissionHeroComp.HERO_POSITIONS[posIndex];
// 不再直接设置位置,而是播放下落入场动画
// 计算出出生点(空中)
const spawnPos: Vec3 = v3(landingPos.x, landingPos.y + MissionHeroComp.HERO_DROP_HEIGHT, 0);
view.node.setPosition(spawnPos);
model.posIndex = posIndex;
if (posIndex >= 0) smc.mission.heroGrid[posIndex] = hero.eid;
hero.playDropAnim(spawnPos, landingPos.y);
}
model.dirty_hp = true;
@@ -171,7 +174,7 @@ export class MissionHeroComp extends CCComp {
* 动态分配英雄上场的位置
* @param excludeEids 排除计算的实体ID数组避免复活或合成时把自己算成占据的位置
*/
private pickPositionForHero(excludeEids: number[] = []): Vec3 {
private pickPositionIndexForHero(excludeEids: number[] = []): number {
const heroes = this.getAllHeroes().filter(h => {
const m = h.get(HeroAttrsComp);
return m && !m.is_dead && !excludeEids.includes(h.eid);
@@ -179,28 +182,20 @@ export class MissionHeroComp extends CCComp {
const occupied = new Set<number>();
for (const h of heroes) {
const move = h.get(MoveComp); // MoveComp 记录了英雄当前的目标位置
if (move) {
for (let i = 0; i < MissionHeroComp.HERO_POSITIONS.length; i++) {
const pos = MissionHeroComp.HERO_POSITIONS[i];
if (Math.abs(move.targetX - pos.x) < 2 && Math.abs(move.baseY - pos.y) < 2) {
occupied.add(i);
break;
}
}
}
const m = h.get(HeroAttrsComp);
if (m && m.posIndex >= 0) occupied.add(m.posIndex);
}
// 优先中前(1) -> 上前(0) -> 下前(2) -> 中后(4) -> 上后(3) -> 下后(5)
const slotPriority = [1, 0, 2, 4, 3, 5];
for (const idx of slotPriority) {
if (!occupied.has(idx)) {
return MissionHeroComp.HERO_POSITIONS[idx];
return idx;
}
}
// 溢出:默认中前
return MissionHeroComp.HERO_POSITIONS[1];
return 1;
}
/**
@@ -217,9 +212,10 @@ export class MissionHeroComp extends CCComp {
console.log("addHero uuid:",uuid)
let hero = ecs.getEntity<Hero>(Hero);
let scale = 1
const landingPos = this.pickPositionForHero();
const posIndex = this.pickPositionIndexForHero();
const landingPos = MissionHeroComp.HERO_POSITIONS[posIndex];
let spawnPos:Vec3 = v3(landingPos.x, landingPos.y + MissionHeroComp.HERO_DROP_HEIGHT, 0);
hero.load(spawnPos,scale,uuid,landingPos.y,hero_lv,pool_lv);
hero.load(spawnPos,scale,uuid,landingPos.y,hero_lv,pool_lv,posIndex);
// 召唤完成后,派发事件以更新英雄面板
const model = hero.get(HeroAttrsComp);
@@ -246,14 +242,19 @@ export class MissionHeroComp extends CCComp {
* @param targetPos 指定生成位置
* @returns 实际生成的英雄等级
*/
private addMergedHero(uuid:number, hero_lv:number, pool_lv:number, ap:number, hp_max:number, targetPos?: Vec3): number {
private addMergedHero(uuid:number, hero_lv:number, pool_lv:number, ap:number, hp_max:number, targetPosIndex?: number, targetPos?: Vec3): number {
console.log("addMergedHero uuid:",uuid)
let hero = ecs.getEntity<Hero>(Hero);
let scale = 1
const landingPos = targetPos || this.pickPositionForHero();
let posIndex = targetPosIndex;
let landingPos = targetPos;
if (posIndex === undefined || posIndex < 0 || !landingPos) {
posIndex = this.pickPositionIndexForHero();
landingPos = MissionHeroComp.HERO_POSITIONS[posIndex];
}
let spawnPos:Vec3 = v3(landingPos.x, landingPos.y + MissionHeroComp.HERO_DROP_HEIGHT, 0);
hero.load(spawnPos,scale,uuid,landingPos.y,hero_lv,pool_lv);
hero.load(spawnPos,scale,uuid,landingPos.y,hero_lv,pool_lv,posIndex);
// 召唤完成后,派发事件以更新英雄面板
const model = hero.get(HeroAttrsComp);
@@ -481,14 +482,14 @@ export class MissionHeroComp extends CCComp {
sumHpMax += model.hp_max;
}
// 计算目标出生点(提前排除素材英雄所占的位置)
const landingPos = this.pickPositionForHero(mergeEids);
const posIndex = this.pickPositionIndexForHero(mergeEids);
const landingPos = MissionHeroComp.HERO_POSITIONS[posIndex];
const spawnPos:Vec3 = v3(landingPos.x, landingPos.y + MissionHeroComp.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, landingPos);
return this.addMergedHero(uuid, Math.min(this.merge_max_lv, hero_lv + 1), pool_lv, sumAp, sumHpMax, posIndex, landingPos);
}
/**