feat: 大幅优化战斗体验与编队系统

1. 扩展英雄/怪物网格站位到10个槽位
2. 重构默认攻击距离计算逻辑,按职业动态适配
3. 重做英雄站位与移动系统,新增同阵营间距约束
4. 调整rogue模式怪物数量与强度配置,提升战斗爽感
5. 重构刷怪逻辑为匀速曲线+欠账补刷,优化刷怪节奏
This commit is contained in:
pan
2026-08-12 17:56:59 +08:00
parent 3060ee7df7
commit a905db8e48
7 changed files with 212 additions and 174 deletions

View File

@@ -223,8 +223,10 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
// 未贴近:向怪物方向推进(攻击范围内也继续移动),于接触距离处停下
const dir = enemyX > selfX ? 1 : -1;
move.direction = dir;
// 终止点取接触距离与推进上限的较小者,防止越过 300 继续追击
const stopX = Math.min(enemyX - dir * MoveSystem.MELEE_ENGAGE_X, MoveSystem.HERO_ADVANCE_LIMIT_X);
// 终止点取接触距离与推进上限的较小者,防止越过 150 继续追击
let stopX = Math.min(enemyX - dir * MoveSystem.MELEE_ENGAGE_X, MoveSystem.HERO_ADVANCE_LIMIT_X);
// 同阵营最小间距约束:防止近战推进时穿越前方队友
stopX = this.clampAllySpacing(e, view, move, model, stopX);
const speed = model.speed / 3;
this.moveEntity(view, dir, speed, stopX);
model.is_atking = false;
@@ -292,7 +294,9 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
/** 近战贴近怪物的固定接触距离:小于攻击距离 dis使英雄进攻击范围后仍继续贴近到此间距才停 */
private static readonly MELEE_ENGAGE_X = 60;
/** 英雄向敌人推进的最远终止点 X防止近战追敌时无限右移脱离战场 */
private static readonly HERO_ADVANCE_LIMIT_X = 300;
private static readonly HERO_ADVANCE_LIMIT_X = 100;
/** 同阵营英雄间最小间距:小于该值时低优先级一方需让位 */
private static readonly ALLY_MIN_GAP_X = 30;
/**
* 计算某个槽位的目标 X。
@@ -328,7 +332,57 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
const dir = targetX > currentX ? 1 : -1;
move.direction = dir;
const speed = model.speed / 3;
this.moveEntity(view, dir, speed, targetX);
// 同阵营最小间距约束:防止编队挤压时穿越前方队友
const clampedTargetX = this.clampAllySpacing(view.ent, view, move, model, targetX);
this.moveEntity(view, dir, speed, clampedTargetX);
}
/**
* 同阵营横向最小间距约束。
* Why: 编队/追击时英雄可能挤到一起,低优先级一方需要保持在高优先级身后 ALLY_MIN_GAP_X 处,
* 避免视觉重叠与站位混乱。
* 优先级编队优先级高者在前同级时召唤早spawnOrder 小)者在前。
* @returns 裁剪后的目标 X保证不越过身前队友
*/
private clampAllySpacing(self: ecs.Entity, view: HeroViewComp, selfMove: MoveComp, model: HeroAttrsComp, targetX: number): number {
const selfX = view.node.position.x;
const selfY = view.node.position.y;
let clamped = targetX;
ecs.query(this.getHeroMoveMatcher()).forEach(e => {
if (e === self) return;
const attrs = e.get(HeroAttrsComp);
const v = e.get(HeroViewComp);
const mv = e.get(MoveComp);
if (!attrs || !v?.node || !mv) return;
if (attrs.is_dead || attrs.is_reviving) return;
if (attrs.fac !== model.fac) return;
// 只约束同排Y 差在阈值内)的队友
if (Math.abs(v.node.position.y - selfY) > this.minSpacingY) return;
const otherX = v.node.position.x;
// 判断对方是否在自己前方(以目标方向为前)
const isAhead = clamped > selfX ? otherX > selfX : otherX < selfX;
if (!isAhead) return;
// 判定谁该在前:编队优先级高者在前;同级时 spawnOrder 小者在前
const myPriority = this.getFormationPriority(model);
const otherPriority = this.getFormationPriority(attrs);
let selfIsFront = false;
if (myPriority !== otherPriority) {
selfIsFront = myPriority > otherPriority;
} else {
selfIsFront = selfMove.spawnOrder <= mv.spawnOrder;
}
if (!selfIsFront) {
// 自己靠后:不能越过 otherX - ALLY_MIN_GAP_X朝右或 otherX + ALLY_MIN_GAP_X朝左
const limitX = clamped > selfX ? otherX - MoveSystem.ALLY_MIN_GAP_X : otherX + MoveSystem.ALLY_MIN_GAP_X;
clamped = clamped > selfX ? Math.min(clamped, limitX) : Math.max(clamped, limitX);
}
});
return clamped;
}
private moveEntity(view: HeroViewComp, direction: number, speed: number, stopAtX?: number) {