refactor: 重构击退机制,将概率改为距离增量

1. 调整近战默认攻击距离从150改为100
2. 将击退相关属性从概率改为击退距离增量,同步更新所有配置、UI显示和技能描述
3. 移除旧的击退概率判定逻辑,改为直接应用击退距离增量
4. 优化受击击退的处理流程,统一参数传递
This commit is contained in:
pan
2026-08-13 11:09:37 +08:00
parent a3375ec3b6
commit eb4b370533
14 changed files with 34 additions and 135 deletions

View File

@@ -136,14 +136,9 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
return dist <= attackRange;
}
/** 同阵营横向最小间距,防止停止移动时完全重叠 */
private static readonly ALLY_MIN_GAP_X = 10;
/** 挤位时的蠕动幅度(像素) */
private static readonly JOSTLE_AMPLITUDE = 2;
/**
* 战斗位移:向最近敌人推进,进入攻击范围后停止。
* 推进无上限限制,可穿越队友;停止移动后受同阵营最小间距约束
* 推进无上限限制,但击退/位移受阵营后退边界保护
*/
private processCombatLogic(_e: ecs.Entity, move: MoveComp, view: HeroViewComp, model: HeroAttrsComp, enemy: HeroViewComp) {
const selfX = view.node.position.x;
@@ -160,10 +155,8 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
if (view.status === "move") {
view.status_change("idle");
}
/** 停止时若与队友重叠,则向后微调保持最小间距,并加入蠕动避免死板 */
this.adjustSpacingWhenIdle(_e, view, move, model);
} else {
/** 未接触:向敌人方向推进(可穿越队友,但同点时后来者稍停) */
/** 未接触:向敌人方向推进 */
model.is_atking = false;
const dir = enemyX > selfX ? 1 : -1;
move.direction = dir;
@@ -171,9 +164,6 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
const delta = speed * this.dt * dir;
let newX = selfX + delta;
/** 推进时若与队友同点,后来者稍停避让 */
newX = this.adjustSpacingWhileMoving(_e, view, move, model, newX, dir);
/** 后退边界钳制:防止被击退/位移推出屏幕 */
newX = this.clampByFacBoundary(newX, model.fac);
@@ -184,93 +174,6 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
}
}
/**
* 推进时的间距避让。
* Why: 允许穿越队友,但若与队友完全同点(重叠),后来者稍停一拍,
* 避免视觉上的"穿模"过于生硬,营造"挤过去"的自然感。
* @returns 调整后的目标 X被阻挡时返回 selfX即本帧不移动
*/
private adjustSpacingWhileMoving(self: ecs.Entity, view: HeroViewComp, selfMove: MoveComp, model: HeroAttrsComp, targetX: number, _dir: number): number {
const selfX = view.node.position.x;
const selfY = view.node.position.y;
let blocked = false;
ecs.query(this.getHeroViewMatcher()).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;
if (Math.abs(v.node.position.y - selfY) > 30) return;
const otherX = v.node.position.x;
/** 同点判定:间距小于最小间距的一半视为完全重叠 */
if (Math.abs(selfX - otherX) < MoveSystem.ALLY_MIN_GAP_X * 0.5) {
/** spawnOrder 大者(后来者)被阻挡 */
if (selfMove.spawnOrder > mv.spawnOrder) {
blocked = true;
}
}
});
return blocked ? selfX : targetX;
}
/**
* 停止移动时的间距微调 + 蠕动效果。
* Why: 允许推进时穿越队友,但进入攻击范围停下后若与队友重叠,
* 则向后微调保持 ALLY_MIN_GAP_X 间距,避免视觉完全重叠。
* 同时加入基于时间的随机蠕动,营造"挤到前方攻击"的生动感。
* Y 轴不变,仅约束 X。
* 优先级spawnOrder 小者(先出生)不动,大者向后让位。
*/
private adjustSpacingWhenIdle(self: ecs.Entity, view: HeroViewComp, selfMove: MoveComp, model: HeroAttrsComp): void {
const selfX = view.node.position.x;
const selfY = view.node.position.y;
let adjustX = selfX;
let isCrowded = false;
ecs.query(this.getHeroViewMatcher()).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) > 30) return;
const otherX = v.node.position.x;
const gap = Math.abs(adjustX - otherX);
if (gap >= MoveSystem.ALLY_MIN_GAP_X) return;
isCrowded = true;
/** spawnOrder 小者不动,大者向后让位 */
if (selfMove.spawnOrder > mv.spawnOrder) {
/** 自己靠后:向远离对方的方向后退到最小间距处 */
const dir = adjustX >= otherX ? 1 : -1;
adjustX = otherX + dir * MoveSystem.ALLY_MIN_GAP_X;
}
});
/** 拥挤时加入蠕动:基于时间+出生序的伪随机偏移,避免多个单位同步抖动 */
if (isCrowded) {
const time = Date.now() / 1000;
const jostlePhase = time * 3 + selfMove.spawnOrder * 0.7; // 不同单位错开相位
const jostleOffset = Math.sin(jostlePhase) * MoveSystem.JOSTLE_AMPLITUDE;
adjustX += jostleOffset;
}
if (Math.abs(adjustX - selfX) >= 0.01) {
/** 后退边界钳制 */
adjustX = this.clampByFacBoundary(adjustX, model.fac);
view.node.setPosition(adjustX, view.node.position.y, 0);
}
}
/**
* 按阵营裁剪 X 坐标,防止被击退/位移推出屏幕。
* HERO 后退不越过 BoxSet.LETF_ENDMON 后退不越过 BoxSet.RIGHT_END。