feat: 大幅优化战斗体验与编队系统

1. 扩展英雄/怪物网格站位到10个槽位
2. 重构默认攻击距离计算逻辑,按职业动态适配
3. 重做英雄站位与移动系统,新增同阵营间距约束
4. 调整rogue模式怪物数量与强度配置,提升战斗爽感
5. 重构刷怪逻辑为匀速曲线+欠账补刷,优化刷怪节奏
This commit is contained in:
pan
2026-08-12 17:56:59 +08:00
parent 3060ee7df7
commit a905db8e48
7 changed files with 212 additions and 174 deletions

View File

@@ -7,7 +7,7 @@ import { HeroViewComp } from "./HeroViewComp";
import { BoxSet, FacSet, FightSet, IndexSet } from "../common/config/GameSet";
import { HeroInfo, HeroPos, resolveFormationTargetX, resolveTriggerByLv, resolveFieldByLv, resolveReviveByLv, calcGrowBonus } from "../common/config/heroSet";
import { GameEvent } from "../common/config/GameEvent";
import { SkillTriggerType } from "../common/config/heroSet";
import { SkillTriggerType, HType } from "../common/config/heroSet";
import { SkillTriggerHelper } from "./SkillTriggerHelper";
import { Attrs } from "../common/config/HeroAttrs";
import { MoveComp } from "./MoveComp";
@@ -122,7 +122,8 @@ export class Hero extends ecs.Entity {
model.grow_type = hero.grow_type;
model.role = hero.role;
model.fac = FacSet.HERO;
model.dis = hero.dis ?? 720;
// 攻击距离配置优先未配置按攻击定位给默认值近战180 / 远程600
model.dis = hero.dis ?? (hero.type === HType.Melee ? 180 : 600);
model.posIndex = posIndex;
if (posIndex >= 0) {
smc.mission.heroGrid[posIndex] = this.eid;

View File

@@ -9,7 +9,7 @@ import { HeroViewComp } from "./HeroViewComp";
import { MoveComp } from "./MoveComp";
import { MonMoveComp } from "./MonMoveComp";
import { GameEvent } from "../common/config/GameEvent";
import { SkillTriggerType } from "../common/config/heroSet";
import { SkillTriggerType, HType } from "../common/config/heroSet";
import { SkillTriggerHelper } from "./SkillTriggerHelper";
/** 怪物实体:负责怪物对象池复用、属性初始化、入场动画与回收 */
@ecs.register(`Monster`)
@@ -175,7 +175,8 @@ export class Monster extends ecs.Entity {
model.speed = hero.speed ?? 800;
model.type = hero.type;
model.fac = FacSet.MON;
model.dis = hero.dis ?? 720;
// 攻击距离配置优先未配置按攻击定位给默认值近战180 / 远程600
model.dis = hero.dis ?? (hero.type === HType.Melee ? 180 : 600);
model.posIndex = laneIndex;
if (laneIndex >= 0) {
smc.mission.monGrid[laneIndex] = this.eid;

View File

@@ -223,8 +223,10 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
// 未贴近:向怪物方向推进(攻击范围内也继续移动),于接触距离处停下
const dir = enemyX > selfX ? 1 : -1;
move.direction = dir;
// 终止点取接触距离与推进上限的较小者,防止越过 300 继续追击
const stopX = Math.min(enemyX - dir * MoveSystem.MELEE_ENGAGE_X, MoveSystem.HERO_ADVANCE_LIMIT_X);
// 终止点取接触距离与推进上限的较小者,防止越过 150 继续追击
let stopX = Math.min(enemyX - dir * MoveSystem.MELEE_ENGAGE_X, MoveSystem.HERO_ADVANCE_LIMIT_X);
// 同阵营最小间距约束:防止近战推进时穿越前方队友
stopX = this.clampAllySpacing(e, view, move, model, stopX);
const speed = model.speed / 3;
this.moveEntity(view, dir, speed, stopX);
model.is_atking = false;
@@ -292,7 +294,9 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
/** 近战贴近怪物的固定接触距离:小于攻击距离 dis使英雄进攻击范围后仍继续贴近到此间距才停 */
private static readonly MELEE_ENGAGE_X = 60;
/** 英雄向敌人推进的最远终止点 X防止近战追敌时无限右移脱离战场 */
private static readonly HERO_ADVANCE_LIMIT_X = 300;
private static readonly HERO_ADVANCE_LIMIT_X = 100;
/** 同阵营英雄间最小间距:小于该值时低优先级一方需让位 */
private static readonly ALLY_MIN_GAP_X = 30;
/**
* 计算某个槽位的目标 X。
@@ -328,7 +332,57 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
const dir = targetX > currentX ? 1 : -1;
move.direction = dir;
const speed = model.speed / 3;
this.moveEntity(view, dir, speed, targetX);
// 同阵营最小间距约束:防止编队挤压时穿越前方队友
const clampedTargetX = this.clampAllySpacing(view.ent, view, move, model, targetX);
this.moveEntity(view, dir, speed, clampedTargetX);
}
/**
* 同阵营横向最小间距约束。
* Why: 编队/追击时英雄可能挤到一起,低优先级一方需要保持在高优先级身后 ALLY_MIN_GAP_X 处,
* 避免视觉重叠与站位混乱。
* 优先级编队优先级高者在前同级时召唤早spawnOrder 小)者在前。
* @returns 裁剪后的目标 X保证不越过身前队友
*/
private clampAllySpacing(self: ecs.Entity, view: HeroViewComp, selfMove: MoveComp, model: HeroAttrsComp, targetX: number): number {
const selfX = view.node.position.x;
const selfY = view.node.position.y;
let clamped = targetX;
ecs.query(this.getHeroMoveMatcher()).forEach(e => {
if (e === self) return;
const attrs = e.get(HeroAttrsComp);
const v = e.get(HeroViewComp);
const mv = e.get(MoveComp);
if (!attrs || !v?.node || !mv) return;
if (attrs.is_dead || attrs.is_reviving) return;
if (attrs.fac !== model.fac) return;
// 只约束同排Y 差在阈值内)的队友
if (Math.abs(v.node.position.y - selfY) > this.minSpacingY) return;
const otherX = v.node.position.x;
// 判断对方是否在自己前方(以目标方向为前)
const isAhead = clamped > selfX ? otherX > selfX : otherX < selfX;
if (!isAhead) return;
// 判定谁该在前:编队优先级高者在前;同级时 spawnOrder 小者在前
const myPriority = this.getFormationPriority(model);
const otherPriority = this.getFormationPriority(attrs);
let selfIsFront = false;
if (myPriority !== otherPriority) {
selfIsFront = myPriority > otherPriority;
} else {
selfIsFront = selfMove.spawnOrder <= mv.spawnOrder;
}
if (!selfIsFront) {
// 自己靠后:不能越过 otherX - ALLY_MIN_GAP_X朝右或 otherX + ALLY_MIN_GAP_X朝左
const limitX = clamped > selfX ? otherX - MoveSystem.ALLY_MIN_GAP_X : otherX + MoveSystem.ALLY_MIN_GAP_X;
clamped = clamped > selfX ? Math.min(clamped, limitX) : Math.max(clamped, limitX);
}
});
return clamped;
}
private moveEntity(view: HeroViewComp, direction: number, speed: number, stopAtX?: number) {