diff --git a/assets/script/game/hero/MoveComp.ts b/assets/script/game/hero/MoveComp.ts index 8ca2331b..3769dcff 100644 --- a/assets/script/game/hero/MoveComp.ts +++ b/assets/script/game/hero/MoveComp.ts @@ -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 {