fix(战斗): 调整远程站位距离并优化移动系统注释与逻辑
- 将远程职业的固定站位X坐标从180减少至120,以改善阵型布局 - 为移动系统组件和配置添加详细注释,说明各字段用途和逻辑规则 - 调整同阵营横向最小间距从40增加至50,减少单位重叠 - 优化近战超车逻辑,明确超车条件和优先级判定 - 改进代码可读性,添加关键逻辑点的解释说明
This commit is contained in:
@@ -23,7 +23,7 @@ export const HeroPos={
|
||||
export const FormationPointX = {
|
||||
[HType.Melee]: 0,
|
||||
[HType.Mid]: 100,
|
||||
[HType.Long]: 180,
|
||||
[HType.Long]: 120,
|
||||
} as const;
|
||||
|
||||
export const HeroDisVal: Record<HType.Melee | HType.Mid | HType.Long, number> = {
|
||||
|
||||
@@ -8,12 +8,19 @@ import { Node } from "cc";
|
||||
|
||||
@ecs.register('MoveComp')
|
||||
export class MoveComp extends ecs.Comp {
|
||||
/** 朝向:1=向右,-1=向左 */
|
||||
direction: number = 1;
|
||||
/** 当前移动目标 X(战斗/回位都会更新) */
|
||||
targetX: number = 0;
|
||||
/** 是否允许移动(出生落地前会短暂关闭) */
|
||||
moving: boolean = true;
|
||||
/** 预留:目标 Y(当前逻辑主要使用 baseY 锁定地平线) */
|
||||
targetY: number = 0;
|
||||
/** 角色所属车道的地平线 Y,移动时强制贴地 */
|
||||
baseY: number = 0;
|
||||
/** 预留:车道索引 */
|
||||
lane: number = 0;
|
||||
/** 出生序,用于同条件渲染排序稳定 */
|
||||
spawnOrder: number = 0;
|
||||
|
||||
reset() {
|
||||
@@ -28,23 +35,37 @@ export class MoveComp extends ecs.Comp {
|
||||
}
|
||||
|
||||
interface MoveFacConfig {
|
||||
/** 阵营可前进边界(靠近敌方一侧) */
|
||||
moveFrontX: number;
|
||||
/** 阵营可后退边界(靠近己方一侧) */
|
||||
moveBackX: number;
|
||||
/** 被逼退时前侧安全边界 */
|
||||
retreatFrontX: number;
|
||||
/** 被逼退时后侧安全边界 */
|
||||
retreatBackX: number;
|
||||
}
|
||||
|
||||
@ecs.register('MoveSystem')
|
||||
export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
||||
/** 近战判定射程(来自 heroSet) */
|
||||
private readonly meleeAttackRange = HeroDisVal[HType.Melee];
|
||||
/** 近战贴脸最小距离,避免完全重叠 */
|
||||
private readonly meleeMinEnemyDistanceX = 60;
|
||||
/** 同优先级近战允许“超车”时,至少要快这么多 */
|
||||
private readonly meleeOvertakeSpeedGap = 20;
|
||||
private readonly allySpacingX = 40;
|
||||
/** 常规同阵营横向最小间距 */
|
||||
private readonly allySpacingX = 50;
|
||||
/** 允许临时压缩站位时的最小间距 */
|
||||
private readonly allyOverlapSpacingX = 14;
|
||||
/** 友军偏离其目标点超过该值,可放宽让路 */
|
||||
private readonly displacementReleaseX = 10;
|
||||
/** 即将进入攻击位的锁定阈值 */
|
||||
private readonly attackReadyLockX = 10;
|
||||
/** 目标距离足够远才触发“借道前压” */
|
||||
private readonly attackPassThresholdX = 60;
|
||||
/** 纵向判定为同排的最大 Y 差 */
|
||||
private readonly minSpacingY = 30;
|
||||
/** 渲染层级重排节流,避免每帧排序 */
|
||||
private readonly renderSortInterval = 0.05;
|
||||
private lastRenderSortAt = 0;
|
||||
private heroMoveMatcher: ecs.IMatcher | null = null;
|
||||
@@ -52,6 +73,10 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
private readonly renderEntries: { node: Node; bossPriority: number; frontScore: number; spawnOrder: number; eid: number }[] = [];
|
||||
private renderEntryCount = 0;
|
||||
|
||||
/**
|
||||
* 阵营可移动边界配置。
|
||||
* HERO 在左侧出生并向右推进;MON 在右侧出生并向左推进。
|
||||
*/
|
||||
private readonly facConfigs: Record<number, MoveFacConfig> = {
|
||||
[FacSet.HERO]: {
|
||||
moveFrontX: 320,
|
||||
@@ -86,6 +111,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
}
|
||||
|
||||
update(e: ecs.Entity) {
|
||||
/** 战斗未开始/暂停时不驱动移动 */
|
||||
if (!smc.mission.play || smc.mission.pause) return;
|
||||
const model = e.get(HeroAttrsComp);
|
||||
const move = e.get(MoveComp);
|
||||
@@ -93,6 +119,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
if (!model || !move || !view || !view.node) return;
|
||||
if (model.fac !== FacSet.HERO && model.fac !== FacSet.MON) return;
|
||||
if (!move.moving) return;
|
||||
/** 关卡阶段性冻结怪物行为 */
|
||||
if (model.fac === FacSet.MON && smc.mission.stop_mon_action) {
|
||||
this.clearCombatTarget(model);
|
||||
view.status_change("idle");
|
||||
@@ -104,15 +131,18 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
return;
|
||||
}
|
||||
|
||||
/** 所有移动都锁定在 baseY,避免出现“漂移” */
|
||||
if (view.node.position.y !== move.baseY) {
|
||||
view.node.setPosition(view.node.position.x, move.baseY, 0);
|
||||
}
|
||||
this.updateRenderOrder(view);
|
||||
const nearestEnemy = this.findNearestEnemy(e);
|
||||
if (nearestEnemy) {
|
||||
/** 有敌人:进入战斗位移逻辑 */
|
||||
this.processCombatLogic(e, move, view, model, nearestEnemy);
|
||||
this.syncCombatTarget(model, view, nearestEnemy);
|
||||
} else {
|
||||
/** 无敌人:清目标并回归编队站位 */
|
||||
this.clearCombatTarget(model);
|
||||
move.targetY = 0;
|
||||
this.processReturnFormation(e, move, view, model);
|
||||
@@ -176,6 +206,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
const maxRange = this.meleeAttackRange;
|
||||
const minRange = Math.min(this.meleeMinEnemyDistanceX, maxRange);
|
||||
|
||||
/** 近战目标点 = 敌人位置 - 朝向 * minRange,确保能贴近但不穿模 */
|
||||
move.direction = enemyX > currentX ? 1 : -1;
|
||||
move.targetX = enemyX - move.direction * minRange;
|
||||
|
||||
@@ -203,6 +234,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
|
||||
private processRangedFormationCombat(move: MoveComp, view: HeroViewComp, model: HeroAttrsComp) {
|
||||
const currentX = view.node.position.x;
|
||||
/** 中/远程不追人:强制回到自己职业站位点输出 */
|
||||
const targetX = this.getFixedFormationX(model);
|
||||
move.targetX = targetX;
|
||||
const needMoveToFormation = Math.abs(currentX - targetX) > 5;
|
||||
@@ -235,6 +267,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
|
||||
private processReturnFormation(e: ecs.Entity, move: MoveComp, view: HeroViewComp, model: HeroAttrsComp) {
|
||||
const currentX = view.node.position.x;
|
||||
/** 脱战时所有类型都回职业站位点,保证阵型稳定 */
|
||||
const targetX = this.getFixedFormationX(model);
|
||||
move.targetX = targetX;
|
||||
|
||||
@@ -255,6 +288,15 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
}
|
||||
|
||||
private getFixedFormationX(model: HeroAttrsComp): number {
|
||||
/**
|
||||
* 站位点来自 heroSet.resolveFormationTargetX:
|
||||
* - 近战 HType.Melee: FormationPointX=0
|
||||
* - 中程 HType.Mid: FormationPointX=100
|
||||
* - 远程 HType.Long: FormationPointX=180
|
||||
* 阵营镜像规则:
|
||||
* - HERO(FacSet.HERO=0):乘 -1 => 近战0 / 中程-100 / 远程-180
|
||||
* - MON(FacSet.MON=1):乘 +1 => 近战0 / 中程100 / 远程180
|
||||
*/
|
||||
return resolveFormationTargetX(model.fac, model.type as HType);
|
||||
}
|
||||
|
||||
@@ -262,6 +304,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
const model = view.ent.get(HeroAttrsComp);
|
||||
const move = view.ent.get(MoveComp);
|
||||
if (!model || !move) return;
|
||||
/** 按阵营边界裁剪,防止跑出战场可移动区域 */
|
||||
const cfg = this.facConfigs[model.fac] || this.facConfigs[FacSet.HERO];
|
||||
const moveMinX = Math.min(cfg.moveBackX, cfg.moveFrontX);
|
||||
const moveMaxX = Math.max(cfg.moveBackX, cfg.moveFrontX);
|
||||
@@ -278,8 +321,10 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
}
|
||||
newX = Math.max(moveMinX, Math.min(moveMaxX, newX));
|
||||
if (stopAtX !== undefined) {
|
||||
/** 指定停止点时,限制不越过 stopAtX */
|
||||
newX = direction > 0 ? Math.min(newX, stopAtX) : Math.max(newX, stopAtX);
|
||||
}
|
||||
/** 结合同排友军占位,做“让位/防重叠”裁剪 */
|
||||
newX = this.clampXByAllies(view.ent, model.fac, move.baseY, currentX, newX, direction);
|
||||
if (direction > 0) {
|
||||
newX = Math.max(currentX, newX);
|
||||
@@ -304,12 +349,14 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
const attrs = e.get(HeroAttrsComp);
|
||||
const view = e.get(HeroViewComp);
|
||||
const allyMove = e.get(MoveComp);
|
||||
/** 只处理同阵营且同排(Y 接近)的友军碰撞约束 */
|
||||
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 (this.shouldAllowMeleeOvertake(selfAttrs, selfMove, attrs, allyMove, currentX, x, direction, allyPriority, selfPriority)) return;
|
||||
const spacing = this.resolveAllySpacing(selfAttrs, selfMove, currentX, direction, allyMove, x, allyPriority, selfPriority);
|
||||
if (direction > 0 && x > currentX) {
|
||||
@@ -334,8 +381,10 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
selfPriority: number
|
||||
): boolean {
|
||||
if (!selfAttrs || !selfMove || !allyMove) return false;
|
||||
/** 仅近战对近战、且同优先级才进入超车判定 */
|
||||
if ((selfAttrs.type as HType) !== HType.Melee || (allyAttrs.type as HType) !== HType.Melee) return false;
|
||||
if (allyPriority !== selfPriority) return false;
|
||||
/** 我方更快,且双方都在前压且友军尚未到可攻击位,允许穿插 */
|
||||
if (selfAttrs.speed <= allyAttrs.speed + this.meleeOvertakeSpeedGap) return false;
|
||||
if (direction > 0 && allyX <= currentX) return false;
|
||||
if (direction < 0 && allyX >= currentX) return false;
|
||||
@@ -361,6 +410,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
allyPriority: number,
|
||||
selfPriority: number
|
||||
): number {
|
||||
/** 默认保持标准间距,仅在“需要抢位输出”时放宽 */
|
||||
if (!selfAttrs || !selfMove || !allyMove) return this.allySpacingX;
|
||||
if ((selfAttrs.type as HType) !== HType.Melee) return this.allySpacingX;
|
||||
if (allyPriority !== selfPriority) return this.allySpacingX;
|
||||
@@ -381,6 +431,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
}
|
||||
|
||||
private getCombatPriority(model: HeroAttrsComp): number {
|
||||
/** 数值越大越靠前:近战 > 中程 > 远程 */
|
||||
const rangeType = model.type as HType.Melee | HType.Mid | HType.Long;
|
||||
if (rangeType === HType.Melee) return 3;
|
||||
if (rangeType === HType.Mid) return 2;
|
||||
@@ -420,7 +471,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
let nearest: HeroViewComp | null = null;
|
||||
let minDis = Infinity;
|
||||
|
||||
// 优化查询:一次遍历
|
||||
/** 一次遍历筛出最近敌人(仅比较 x 轴距离) */
|
||||
ecs.query(this.getHeroViewMatcher()).forEach(e => {
|
||||
const m = e.get(HeroAttrsComp);
|
||||
if (m.fac !== myFac && !m.is_dead) {
|
||||
@@ -476,6 +527,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
});
|
||||
this.renderEntries.length = this.renderEntryCount;
|
||||
|
||||
/** 定时重排同层节点:Boss 优先级 -> 前后位置 -> 出生序 -> eid */
|
||||
this.renderEntries.sort((a, b) => {
|
||||
if (a.bossPriority !== b.bossPriority) return a.bossPriority - b.bossPriority;
|
||||
if (a.frontScore !== b.frontScore) return a.frontScore - b.frontScore;
|
||||
|
||||
Reference in New Issue
Block a user