refactor(hero): 统一英雄攻击射程配置并优化射程判断
1. 将MoveSystem和MonMoveSystem中的硬编码射程常量替换为HeroDisVal统一配置 2. 调整近战英雄默认攻击射程为120,修正原硬编码数值不一致问题 3. 优化施法射程计算逻辑,复用HeroDisVal配置 4. 为敌人查找逻辑添加同路优先筛选逻辑 5. 修正部分英雄技能的弹道类型为贝塞尔曲线 6. 移除冗余的射程常量定义,统一配置管理
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 生成沿目标方向的施法目标坐标 */
|
/** 生成沿目标方向的施法目标坐标 */
|
||||||
|
|||||||
Reference in New Issue
Block a user