From ad5758c6e7fbfdec1b3bdf92423680f2599c85ab Mon Sep 17 00:00:00 2001 From: panw Date: Fri, 27 Mar 2026 10:08:11 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E6=88=98=E6=96=97):=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E8=BF=9C=E7=A8=8B=E7=AB=99=E4=BD=8D=E8=B7=9D=E7=A6=BB=E5=B9=B6?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=A7=BB=E5=8A=A8=E7=B3=BB=E7=BB=9F=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=E4=B8=8E=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将远程职业的固定站位X坐标从180减少至120,以改善阵型布局 - 为移动系统组件和配置添加详细注释,说明各字段用途和逻辑规则 - 调整同阵营横向最小间距从40增加至50,减少单位重叠 - 优化近战超车逻辑,明确超车条件和优先级判定 - 改进代码可读性,添加关键逻辑点的解释说明 --- assets/script/game/common/config/heroSet.ts | 2 +- assets/script/game/hero/MoveComp.ts | 56 ++++++++++++++++++++- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/assets/script/game/common/config/heroSet.ts b/assets/script/game/common/config/heroSet.ts index 2e5c9a8b..17ebb7e4 100644 --- a/assets/script/game/common/config/heroSet.ts +++ b/assets/script/game/common/config/heroSet.ts @@ -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 = { diff --git a/assets/script/game/hero/MoveComp.ts b/assets/script/game/hero/MoveComp.ts index c5f168d9..0847878a 100644 --- a/assets/script/game/hero/MoveComp.ts +++ b/assets/script/game/hero/MoveComp.ts @@ -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 = { [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;