fix(移动): 优化盟友间距计算以允许目标重叠

引入 allyOverlapSpacingX 和 displacementReleaseX 常量,在特定条件下允许盟友目标位置重叠。
当盟友已被显著位移且自身需要前进时,使用更小的间距,避免不必要的移动阻塞。
This commit is contained in:
panw
2026-03-18 09:22:46 +08:00
parent d91f32942e
commit 08af676c84

View File

@@ -38,6 +38,8 @@ interface MoveFacConfig {
export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
private readonly meleeAttackRange = 52;
private readonly allySpacingX = 40;
private readonly allyOverlapSpacingX = 8;
private readonly displacementReleaseX = 24;
private readonly minSpacingY = 30;
private readonly renderSortInterval = 0.05;
private renderSortElapsed = 0;
@@ -170,14 +172,14 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
const maxRange = this.meleeAttackRange;
move.direction = enemyX > currentX ? 1 : -1;
move.targetX = enemyX - move.direction * maxRange;
if (dist <= maxRange) {
view.status_change("idle");
model.is_atking = true;
} else {
const speed = model.speed / 3;
const stopAtX = enemyX - move.direction * maxRange;
this.moveEntity(view, move.direction, speed, stopAtX);
this.moveEntity(view, move.direction, speed, move.targetX);
model.is_atking = true;
}
}
@@ -289,30 +291,52 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
private clampXByAllies(self: ecs.Entity, fac: number, baseY: number, currentX: number, proposedX: number, direction: number): number {
const selfAttrs = self.get(HeroAttrsComp);
const selfMove = self.get(MoveComp);
const selfPriority = selfAttrs ? this.getCombatPriority(selfAttrs) : 0;
let nearestAheadX = Infinity;
let nearestBehindX = -Infinity;
let clampedX = proposedX;
ecs.query(this.getHeroMoveMatcher()).forEach(e => {
if (e === self) return;
const attrs = e.get(HeroAttrsComp);
const view = e.get(HeroViewComp);
const allyMove = e.get(MoveComp);
if (!attrs || !view?.node || attrs.is_dead) return;
if (attrs.fac !== fac) return;
if (Math.abs(view.node.position.y - baseY) >= this.minSpacingY) return;
const allyPriority = this.getCombatPriority(attrs);
if (allyPriority < selfPriority) return;
const x = view.node.position.x;
if (x > currentX && x < nearestAheadX) nearestAheadX = x;
if (x < currentX && x > nearestBehindX) nearestBehindX = x;
const spacing = this.resolveAllySpacing(selfAttrs, selfMove, currentX, direction, allyMove, x, allyPriority, selfPriority);
if (direction > 0 && x > currentX) {
clampedX = Math.min(clampedX, x - spacing);
}
if (direction < 0 && x < currentX) {
clampedX = Math.max(clampedX, x + spacing);
}
});
return clampedX;
}
if (direction > 0 && nearestAheadX !== Infinity) {
return Math.min(proposedX, nearestAheadX - this.allySpacingX);
}
if (direction < 0 && nearestBehindX !== -Infinity) {
return Math.max(proposedX, nearestBehindX + this.allySpacingX);
}
return proposedX;
private resolveAllySpacing(
selfAttrs: HeroAttrsComp | null,
selfMove: MoveComp | null,
currentX: number,
direction: number,
allyMove: MoveComp | null,
allyX: number,
allyPriority: number,
selfPriority: number
): number {
if (!selfAttrs || !selfMove || !allyMove) return this.allySpacingX;
if (allyPriority !== selfPriority) return this.allySpacingX;
const selfTargetX = selfMove.targetX;
const allyTargetX = allyMove.targetX;
const selfHasTarget = Math.abs(selfTargetX) > 0.01;
const allyHasTarget = Math.abs(allyTargetX) > 0.01;
if (!selfHasTarget || !allyHasTarget) return this.allySpacingX;
const allyDisplaced = Math.abs(allyX - allyTargetX) >= this.displacementReleaseX;
const selfNeedAdvance = direction > 0 ? selfTargetX > currentX + 2 : selfTargetX < currentX - 2;
if (allyDisplaced && selfNeedAdvance) return this.allyOverlapSpacingX;
return this.allySpacingX;
}
private getCombatPriority(model: HeroAttrsComp): number {