refactor(hero): 统一英雄攻击射程配置并优化射程判断

1.  将MoveSystem和MonMoveSystem中的硬编码射程常量替换为HeroDisVal统一配置
2.  调整近战英雄默认攻击射程为120,修正原硬编码数值不一致问题
3.  优化施法射程计算逻辑,复用HeroDisVal配置
4.  为敌人查找逻辑添加同路优先筛选逻辑
5.  修正部分英雄技能的弹道类型为贝塞尔曲线
6.  移除冗余的射程常量定义,统一配置管理
This commit is contained in:
panw
2026-05-12 16:32:38 +08:00
parent 20e9b1d484
commit 9b35482b3c
5 changed files with 53 additions and 28 deletions

View File

@@ -193,7 +193,7 @@ export const SkillSet: Record<number, SkillConfig> = {
6001: { 6001: {
uuid:6001,name:t("skill_name_6001"),sp_name:"atk",icon:"1026",TGroup:TGroup.Enemy,readyAnm:"",endAnm:"",act:"atk", uuid:6001,name:t("skill_name_6001"),sp_name:"atk",icon:"1026",TGroup:TGroup.Enemy,readyAnm:"",endAnm:"",act:"atk",
DTType:DTType.single,ap:100,hit_count:1,hitcd:0.2,speed:720,with:0,ready:0.2,EAnm:0,DAnm:"",IType:IType.Melee, DTType:DTType.single,ap:100,hit_count:1,hitcd:0.2,speed:720,with:0,ready:0.2,EAnm:0,DAnm:"",IType:IType.Melee,
RType:RType.linear,EType:EType.collision,buffs:[],info:t("skill_info_6001", 1, 100), RType:RType.bezier,EType:EType.collision,buffs:[],info:t("skill_info_6001", 1, 100),
}, },
6002: { 6002: {
uuid:6002,name:t("skill_name_6002"),sp_name:"ball_fire",icon:"1126",TGroup:TGroup.Enemy,readyAnm:"",endAnm:"",act:"atk", uuid:6002,name:t("skill_name_6002"),sp_name:"ball_fire",icon:"1126",TGroup:TGroup.Enemy,readyAnm:"",endAnm:"",act:"atk",
@@ -208,7 +208,7 @@ export const SkillSet: Record<number, SkillConfig> = {
6004: { 6004: {
uuid:6004,name:t("skill_name_6004"),sp_name:"ball_zi",icon:"1126",TGroup:TGroup.Enemy,readyAnm:"",endAnm:"",act:"atk", uuid:6004,name:t("skill_name_6004"),sp_name:"ball_zi",icon:"1126",TGroup:TGroup.Enemy,readyAnm:"",endAnm:"",act:"atk",
DTType:DTType.single,ap:100,hit_count:1,hitcd:0.3,speed:720,with:90,ready:0.2,EAnm:0,DAnm:"",IType:IType.remote, DTType:DTType.single,ap:100,hit_count:1,hitcd:0.3,speed:720,with:90,ready:0.2,EAnm:0,DAnm:"",IType:IType.remote,
RType:RType.linear,EType:EType.collision,buffs:[],info:t("skill_info_6004", 1, 100), RType:RType.bezier,EType:EType.collision,buffs:[],info:t("skill_info_6004", 1, 100),
}, },
6005: { 6005: {
uuid:6005,name:t("skill_name_6005"),sp_name:"arrow",icon:"1135",TGroup:TGroup.Enemy,readyAnm:"",endAnm:"",act:"atk", uuid:6005,name:t("skill_name_6005"),sp_name:"arrow",icon:"1135",TGroup:TGroup.Enemy,readyAnm:"",endAnm:"",act:"atk",
@@ -248,7 +248,7 @@ export const SkillSet: Record<number, SkillConfig> = {
6104: { 6104: {
uuid:6104,name:t("skill_name_6104"),sp_name:"arrow_big_yellow",icon:"1135",TGroup:TGroup.Enemy,readyAnm:"yellow",endAnm:"",act:"max", uuid:6104,name:t("skill_name_6104"),sp_name:"arrow_big_yellow",icon:"1135",TGroup:TGroup.Enemy,readyAnm:"yellow",endAnm:"",act:"max",
DTType:DTType.single,crt:20,ap:100,hit_count:6,hitcd:0.2,speed:720,with:0,ready:0.2,EAnm:0,DAnm:"",IType:IType.remote, DTType:DTType.single,crt:20,ap:100,hit_count:6,hitcd:0.2,speed:720,with:0,ready:0.2,EAnm:0,DAnm:"",IType:IType.remote,
RType:RType.linear,EType:EType.collision,buffs:[],info:t("skill_info_6104", 6, 100), RType:RType.bezier,EType:EType.collision,buffs:[],info:t("skill_info_6104", 6, 100),
}, },
6105: { 6105: {
uuid:6105,name:t("skill_name_6105"),sp_name:"atk_fire",icon:"1173",TGroup:TGroup.Enemy,readyAnm:"blues",endAnm:"",act:"max", uuid:6105,name:t("skill_name_6105"),sp_name:"atk_fire",icon:"1173",TGroup:TGroup.Enemy,readyAnm:"blues",endAnm:"",act:"max",

View File

@@ -69,7 +69,7 @@ export const FormationPointX = {
} as const; } as const;
export const HeroDisVal: Record<HType.Melee | HType.Mid | HType.Long, number> = { export const HeroDisVal: Record<HType.Melee | HType.Mid | HType.Long, number> = {
[HType.Melee]: 720, [HType.Melee]: 120,
[HType.Mid]: 720, [HType.Mid]: 720,
[HType.Long]: 720, [HType.Long]: 720,
} }
@@ -207,7 +207,7 @@ export const HeroInfo: Record<number, heroInfo> = {
6001:{uuid:6001,name:t("mon_name_6001"),path:"mo1", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:120,ap:12,speed:100, 6001:{uuid:6001,name:t("mon_name_6001"),path:"mo1", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:120,ap:12,speed:100,
skills:{6001:{uuid:6001,lv:1,cd:0.65,ccd:0}},info:""}, skills:{6001:{uuid:6001,lv:1,cd:0.65,ccd:0}},info:""},
6002:{uuid:6002,name:t("mon_name_6002"),path:"mo3", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:120,ap:12,speed:100, 6002:{uuid:6002,name:t("mon_name_6002"),path:"mo3", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:120,ap:12,speed:100,
skills:{6001:{uuid:6001,lv:1,cd:0.65,ccd:0},6004:{uuid:6004,lv:1,cd:10,ccd:0}},info:""}, skills:{6001:{uuid:6001,lv:1,cd:0.65,ccd:0}},info:""},
6003:{uuid:6003,name:t("mon_name_6003"),path:"mo4", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:350,ap:30,speed:100, 6003:{uuid:6003,name:t("mon_name_6003"),path:"mo4", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:350,ap:30,speed:100,
skills:{6001:{uuid:6001,lv:1,cd:2,ccd:0}},info:""}, skills:{6001:{uuid:6001,lv:1,cd:2,ccd:0}},info:""},
// 4. 远程 // 4. 远程
@@ -217,7 +217,7 @@ export const HeroInfo: Record<number, heroInfo> = {
skills:{6001:{uuid:6203,lv:1,cd:1.5,ccd:0}},info:""}, skills:{6001:{uuid:6203,lv:1,cd:1.5,ccd:0}},info:""},
// 6. 精英/BOSS型 // 6. 精英/BOSS型
6006:{uuid:6006,name:t("mon_name_6006"),path:"mo6", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:1500,ap:20,speed:100, 6006:{uuid:6006,name:t("mon_name_6006"),path:"mo6", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:1500,ap:20,speed:100,
skills:{6002:{uuid:6002,lv:1,cd:2,ccd:0},6004:{uuid:6004,lv:1,cd:10,ccd:0}},info:""}, skills:{6002:{uuid:6002,lv:1,cd:2,ccd:0}},info:""},
//============== 亡灵系列 =============== //============== 亡灵系列 ===============
// 近战型 // 近战型
6101:{uuid:6101,name:t("mon_name_6101"),path:"mud1", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:120,ap:12,speed:100, 6101:{uuid:6101,name:t("mon_name_6101"),path:"mud1", fac:FacSet.MON,cards_lv:1,lv:1,type:HType.Melee,hp:120,ap:12,speed:100,

View File

@@ -30,10 +30,6 @@ export class MonMoveComp extends ecs.Comp {
@ecs.register('MonMoveSystem') @ecs.register('MonMoveSystem')
export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
/** 近战判定射程 */
private readonly meleeAttackRange = 250;
/** 远程判定射程 */
private readonly longAttackRange = 600;
/** 渲染层级重排节流,避免每帧排序 */ /** 渲染层级重排节流,避免每帧排序 */
private readonly renderSortInterval = 0.05; private readonly renderSortInterval = 0.05;
private lastRenderSortAt = 0; private lastRenderSortAt = 0;
@@ -128,8 +124,8 @@ export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
private isEnemyInAttackRange(model: HeroAttrsComp, selfX: number, enemyX: number): boolean { private isEnemyInAttackRange(model: HeroAttrsComp, selfX: number, enemyX: number): boolean {
const dist = Math.abs(selfX - enemyX); const dist = Math.abs(selfX - enemyX);
const rangeType = model.type as HType.Melee | HType.Mid | HType.Long; const rangeType = model.type as HType.Melee | HType.Mid | HType.Long;
if (rangeType === HType.Melee) return dist <= this.meleeAttackRange; const attackRange = HeroDisVal[rangeType];
return dist <= this.longAttackRange; return dist <= attackRange;
} }
private processCombatLogic(e: ecs.Entity, move: MonMoveComp, view: HeroViewComp, model: HeroAttrsComp, enemy: HeroViewComp) { private processCombatLogic(e: ecs.Entity, move: MonMoveComp, view: HeroViewComp, model: HeroAttrsComp, enemy: HeroViewComp) {

View File

@@ -48,10 +48,6 @@ interface MoveFacConfig {
@ecs.register('MoveSystem') @ecs.register('MoveSystem')
export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
/** 近战判定射程 */
private readonly meleeAttackRange = 250;
/** 远程判定射程 */
private readonly longAttackRange = 600;
private readonly heroFrontAnchorX = -100; private readonly heroFrontAnchorX = -100;
private readonly monFrontAnchorX = 0; private readonly monFrontAnchorX = 0;
/** 常规同阵营横向最小间距(英雄) */ /** 常规同阵营横向最小间距(英雄) */
@@ -166,8 +162,8 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
private isEnemyInAttackRange(model: HeroAttrsComp, selfX: number, enemyX: number): boolean { private isEnemyInAttackRange(model: HeroAttrsComp, selfX: number, enemyX: number): boolean {
const dist = Math.abs(selfX - enemyX); const dist = Math.abs(selfX - enemyX);
const rangeType = model.type as HType.Melee | HType.Mid | HType.Long; const rangeType = model.type as HType.Melee | HType.Mid | HType.Long;
if (rangeType === HType.Melee) return dist <= this.meleeAttackRange; const attackRange = HeroDisVal[rangeType];
return dist <= this.longAttackRange; return dist <= attackRange;
} }
private processCombatLogic(e: ecs.Entity, move: MoveComp, view: HeroViewComp, model: HeroAttrsComp, enemy: HeroViewComp) { private processCombatLogic(e: ecs.Entity, move: MoveComp, view: HeroViewComp, model: HeroAttrsComp, enemy: HeroViewComp) {

View File

@@ -5,7 +5,7 @@ import { HeroViewComp } from "./HeroViewComp";
import { DTType, RType, SkillConfig, SkillKind, SkillSet, SkillUpList, TGroup } from "../common/config/SkillSet"; import { DTType, RType, SkillConfig, SkillKind, SkillSet, SkillUpList, TGroup } from "../common/config/SkillSet";
import { Skill } from "../skill/Skill"; import { Skill } from "../skill/Skill";
import { smc } from "../common/SingletonModuleComp"; import { smc } from "../common/SingletonModuleComp";
import { HeroInfo, HType } from "../common/config/heroSet"; import { HeroDisVal, HeroInfo, HType } from "../common/config/heroSet";
import { Attrs } from "../common/config/HeroAttrs"; import { Attrs } from "../common/config/HeroAttrs";
import { BoxSet, FacSet, FightSet } from "../common/config/GameSet"; import { BoxSet, FacSet, FightSet } from "../common/config/GameSet";
import { oops } from "db://oops-framework/core/Oops"; import { oops } from "db://oops-framework/core/Oops";
@@ -140,8 +140,6 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
} }
/** 空施法计划:用于“当前无可施法技能”时的统一返回 */ /** 空施法计划:用于“当前无可施法技能”时的统一返回 */
private readonly emptyCastPlan = { skillId: 0, skillLv: 1, isFriendly: false, targetPos: null as Vec3 | null, targetEids: [] as number[] }; private readonly emptyCastPlan = { skillId: 0, skillLv: 1, isFriendly: false, targetPos: null as Vec3 | null, targetEids: [] as number[] };
/** 近战英雄默认施法射程 */
private readonly meleeCastRange = 64;
/** 查询缓存:避免每帧重复创建 matcher */ /** 查询缓存:避免每帧重复创建 matcher */
private heroMatcher: ecs.IMatcher | null = null; private heroMatcher: ecs.IMatcher | null = null;
@@ -543,12 +541,16 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
/** /**
* 在施法距离内查找最近敌人。 * 在施法距离内查找最近敌人。
* 用于单体技能与基础目标参考。 * 用于单体技能与基础目标参考。
* 考虑三路设计同路Y差较小优先如果同路没有目标再考虑跨路
*/ */
private findNearestEnemyInRange(heroAttrs: HeroAttrsComp, heroView: HeroViewComp, maxRange: number): HeroViewComp | null { private findNearestEnemyInRange(heroAttrs: HeroAttrsComp, heroView: HeroViewComp, maxRange: number): HeroViewComp | null {
if (!heroView.node) return null; if (!heroView.node) return null;
const currentX = heroView.node.position.x; const currentX = heroView.node.position.x;
const currentY = heroView.node.position.y;
let nearest: HeroViewComp | null = null; let nearest: HeroViewComp | null = null;
let minDist = Infinity; let minDist = Infinity;
let foundSameLane = false;
ecs.query(this.getHeroMatcher()).forEach(entity => { ecs.query(this.getHeroMatcher()).forEach(entity => {
const attrs = entity.get(HeroAttrsComp); const attrs = entity.get(HeroAttrsComp);
const view = entity.get(HeroViewComp); const view = entity.get(HeroViewComp);
@@ -556,10 +558,26 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
if (attrs.fac === heroAttrs.fac) return; if (attrs.fac === heroAttrs.fac) return;
if (attrs.is_dead || attrs.is_reviving) return; if (attrs.is_dead || attrs.is_reviving) return;
if (this.isOutOfBattleBounds(view.node.position.x)) return; if (this.isOutOfBattleBounds(view.node.position.x)) return;
const dist = Math.abs(currentX - view.node.position.x);
if (dist > maxRange) return; const distX = Math.abs(currentX - view.node.position.x);
if (dist >= minDist) return; if (distX > maxRange) return;
minDist = dist;
const isSameLane = Math.abs(currentY - view.node.position.y) < 30; // 30为容差
// 如果之前找到了同路目标,且当前不是同路,直接跳过
if (foundSameLane && !isSameLane) return;
// 如果当前是同路,且之前没找到同路,则强制替换(同路优先)
if (isSameLane && !foundSameLane) {
foundSameLane = true;
minDist = distX;
nearest = view;
return;
}
// 同等路况下比较距离
if (distX >= minDist) return;
minDist = distX;
nearest = view; nearest = view;
}); });
return nearest; return nearest;
@@ -568,13 +586,17 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
/** /**
* 在施法距离内查找“最前排”敌人。 * 在施法距离内查找“最前排”敌人。
* 依据施法者面向方向选择 x 轴上更前的目标。 * 依据施法者面向方向选择 x 轴上更前的目标。
* 考虑三路设计:同路优先
*/ */
private findFrontEnemyInRange(heroAttrs: HeroAttrsComp, heroView: HeroViewComp, maxRange: number, nearestEnemy: HeroViewComp): HeroViewComp | null { private findFrontEnemyInRange(heroAttrs: HeroAttrsComp, heroView: HeroViewComp, maxRange: number, nearestEnemy: HeroViewComp): HeroViewComp | null {
if (!heroView.node || !nearestEnemy.node) return null; if (!heroView.node || !nearestEnemy.node) return null;
const currentX = heroView.node.position.x; const currentX = heroView.node.position.x;
const currentY = heroView.node.position.y;
const direction = nearestEnemy.node.position.x >= currentX ? 1 : -1; const direction = nearestEnemy.node.position.x >= currentX ? 1 : -1;
let frontEnemy: HeroViewComp | null = null; let frontEnemy: HeroViewComp | null = null;
let edgeX = direction > 0 ? Infinity : -Infinity; let edgeX = direction > 0 ? Infinity : -Infinity;
let foundSameLane = false;
ecs.query(this.getHeroMatcher()).forEach(entity => { ecs.query(this.getHeroMatcher()).forEach(entity => {
const attrs = entity.get(HeroAttrsComp); const attrs = entity.get(HeroAttrsComp);
const view = entity.get(HeroViewComp); const view = entity.get(HeroViewComp);
@@ -583,8 +605,20 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
if (attrs.is_dead || attrs.is_reviving) return; if (attrs.is_dead || attrs.is_reviving) return;
const enemyX = view.node.position.x; const enemyX = view.node.position.x;
if (this.isOutOfBattleBounds(enemyX)) return; if (this.isOutOfBattleBounds(enemyX)) return;
const dist = Math.abs(currentX - enemyX); const dist = Math.abs(currentX - enemyX);
if (dist > maxRange) return; if (dist > maxRange) return;
const isSameLane = Math.abs(currentY - view.node.position.y) < 30;
if (foundSameLane && !isSameLane) return;
if (isSameLane && !foundSameLane) {
foundSameLane = true;
edgeX = enemyX;
frontEnemy = view;
return;
}
if (direction > 0) { if (direction > 0) {
if (enemyX >= edgeX) return; if (enemyX >= edgeX) return;
edgeX = enemyX; edgeX = enemyX;
@@ -618,9 +652,8 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
private resolveMaxCastRange(heroAttrs: HeroAttrsComp, type: HType): number { private resolveMaxCastRange(heroAttrs: HeroAttrsComp, type: HType): number {
const cached = heroAttrs.getCachedMaxSkillDistance(); const cached = heroAttrs.getCachedMaxSkillDistance();
if (cached > 0) return cached; if (cached > 0) return cached;
if (type === HType.Long) return 720; const rangeType = type as HType.Melee | HType.Mid | HType.Long;
if (type === HType.Mid) return 360; return HeroDisVal[rangeType];
return this.meleeCastRange;
} }
/** 生成沿目标方向的施法目标坐标 */ /** 生成沿目标方向的施法目标坐标 */