From 20aa067c9ca6c081fea91e8de657c298747aee43 Mon Sep 17 00:00:00 2001 From: panw Date: Tue, 17 Mar 2026 17:00:01 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E6=88=98=E6=96=97):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E8=8B=B1=E9=9B=84=E7=A7=BB=E5=8A=A8=E5=92=8C=E6=96=BD=E6=B3=95?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移动系统现在会在需要保持距离时也执行移动,避免过于靠近敌人 - 施法系统重构目标选择逻辑,确保在射程内寻找最近敌人 - 添加近战施法距离常量,根据英雄类型动态计算最大施法范围 - 移除不必要的攻击状态检查,优化施法条件判断 --- assets/script/game/hero/MoveComp.ts | 4 +- assets/script/game/hero/SCastSystem.ts | 58 ++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/assets/script/game/hero/MoveComp.ts b/assets/script/game/hero/MoveComp.ts index ae917fbb..8ca2331b 100644 --- a/assets/script/game/hero/MoveComp.ts +++ b/assets/script/game/hero/MoveComp.ts @@ -198,8 +198,8 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate const [minRange, maxRange] = this.resolveCombatRange(model, defaultMin, defaultMax); const dist = Math.abs(currentX - enemyX); const needMoveToFormation = Math.abs(currentX - targetX) > 5; - - if (dist >= minRange && needMoveToFormation) { + const shouldKeepDistance = dist < minRange; + if (needMoveToFormation || shouldKeepDistance) { const dir = targetX > currentX ? 1 : -1; move.direction = dir; const speed = model.speed / 3; diff --git a/assets/script/game/hero/SCastSystem.ts b/assets/script/game/hero/SCastSystem.ts index 1c36fb94..519febc8 100644 --- a/assets/script/game/hero/SCastSystem.ts +++ b/assets/script/game/hero/SCastSystem.ts @@ -8,6 +8,7 @@ import { smc } from "../common/SingletonModuleComp"; import { GameConst } from "../common/config/GameConst"; import { oops } from "db://oops-framework/core/Oops"; import { GameEvent } from "../common/config/GameEvent"; +import { HType } from "../common/config/heroSet"; /** * ==================== 自动施法系统 ==================== @@ -25,6 +26,7 @@ import { GameEvent } from "../common/config/GameEvent"; export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { debugMode: boolean = false; // 是否启用调试模式 private readonly emptyCastPlan = { skillId: 0, targets: [] as HeroViewComp[], isFriendly: false }; + private readonly meleeCastRange = 64; filter(): ecs.IMatcher { return ecs.allOf(HeroAttrsComp, HeroViewComp); @@ -38,13 +40,13 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate if (!heroAttrs || !heroView || !heroView.node) return; if (heroAttrs.is_dead || heroAttrs.is_reviving || heroAttrs.isStun() || heroAttrs.isFrost()) return; heroAttrs.updateCD(this.dt); - if (!heroAttrs.is_atking) return; const castPlan = this.pickCastSkill(heroAttrs, heroView); if (castPlan.skillId === 0 || castPlan.targets.length === 0) return; this.castSkill(e, castPlan, heroAttrs, heroView); } private pickCastSkill(heroAttrs: HeroAttrsComp, heroView: HeroViewComp): { skillId: number; targets: HeroViewComp[]; isFriendly: boolean } { + const { target, inRange } = this.resolveCastTarget(heroAttrs, heroView); const skillCandidates = [heroAttrs.skill_id, heroAttrs.atk_id]; for (const s_uuid of skillCandidates) { if (!s_uuid) continue; @@ -56,9 +58,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate if (this.isFriendlySkill(config.TGroup)) { return { skillId: s_uuid, targets: [heroView], isFriendly: true }; } - if (!heroAttrs.enemy_in_cast_range) continue; - const target = this.resolveCombatTarget(heroAttrs); - if (!target) continue; + if (!target || !inRange) continue; return { skillId: s_uuid, targets: [target], isFriendly: false }; } return this.emptyCastPlan; @@ -177,4 +177,54 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate if (targetAttrs.fac === heroAttrs.fac) return null; return targetView; } + + private resolveCastTarget(heroAttrs: HeroAttrsComp, heroView: HeroViewComp): { target: HeroViewComp | null; inRange: boolean } { + const combatTarget = this.resolveCombatTarget(heroAttrs); + if (combatTarget && this.isEnemyInCastRange(heroAttrs, heroView, combatTarget)) { + return { target: combatTarget, inRange: true }; + } + const nearestInRange = this.findNearestEnemy(heroAttrs, heroView, true); + if (nearestInRange) { + return { target: nearestInRange, inRange: true }; + } + const fallback = combatTarget ?? this.findNearestEnemy(heroAttrs, heroView, false); + if (!fallback) return { target: null, inRange: false }; + return { target: fallback, inRange: this.isEnemyInCastRange(heroAttrs, heroView, fallback) }; + } + + private findNearestEnemy(heroAttrs: HeroAttrsComp, heroView: HeroViewComp, requireInRange: boolean): HeroViewComp | null { + if (!heroView.node) return null; + const currentX = heroView.node.position.x; + let nearest: HeroViewComp | null = null; + let minDist = Infinity; + ecs.query(this.filter()).forEach(entity => { + const attrs = entity.get(HeroAttrsComp); + const view = entity.get(HeroViewComp); + if (!attrs || !view?.node) return; + if (attrs.fac === heroAttrs.fac) return; + if (attrs.is_dead || attrs.is_reviving) return; + const dist = Math.abs(currentX - view.node.position.x); + if (requireInRange && !this.isEnemyInCastRange(heroAttrs, heroView, view)) return; + if (dist >= minDist) return; + minDist = dist; + nearest = view; + }); + return nearest; + } + + private isEnemyInCastRange(heroAttrs: HeroAttrsComp, heroView: HeroViewComp, target: HeroViewComp): boolean { + if (!heroView.node || !target.node) return false; + const dist = Math.abs(heroView.node.position.x - target.node.position.x); + const type = heroAttrs.type as HType; + const maxRange = this.resolveMaxCastRange(heroAttrs, type); + return dist <= maxRange; + } + + private resolveMaxCastRange(heroAttrs: HeroAttrsComp, type: HType): number { + const cached = heroAttrs.getCachedMaxSkillDistance(); + if (cached > 0) return cached; + if (type === HType.Long) return 720; + if (type === HType.Mid) return 360; + return this.meleeCastRange; + } }