feat(monster): 调整怪物AI并重构刷怪系统
重构怪物移动逻辑,移除移动追击相关代码,改为定点攻击模式,无敌人时原地待机,仅根据攻击范围切换攻击状态与朝向。 重构波次刷怪逻辑,删除分段刷怪阶段处理,改为波次准备结束后批量生成所有怪物。 将原6路刷怪改为3行网格布局,调整怪物出生点的X轴起点与间距。 限制单波最大怪物数量为12,简化刷怪分配逻辑为按生成顺序自动排列行列。 清理冗余的运行时状态变量与废弃函数,优化代码整体结构。 BREAKING CHANGES: 怪物攻击逻辑从移动追击改为定点攻击,移除了MonMoveComp中的moveEntity和resolveCombatRange函数;刷怪系统从6路改为3行网格布局,移除了分段刷怪功能与相关状态变量。
This commit is contained in:
@@ -86,19 +86,19 @@ export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
|
||||
}
|
||||
// 渲染层级统交由 MoveSystem 统一处理,避免两个 System 争抢 setSiblingIndex
|
||||
|
||||
// 仅在战斗中才处理索敌和移动
|
||||
// 仅在战斗中才处理索敌
|
||||
if (!smc.mission.in_fight) return;
|
||||
|
||||
const nearestEnemy = this.findNearestEnemy(e);
|
||||
if (nearestEnemy) {
|
||||
/** 有敌人:进入战斗位移逻辑 */
|
||||
/** 有敌人:进入固定位置攻击逻辑 */
|
||||
this.processCombatLogic(e, move, view, model, nearestEnemy);
|
||||
this.syncCombatTarget(model, view, nearestEnemy);
|
||||
} else {
|
||||
/** 无敌人:继续向左推进 */
|
||||
/** 无敌人:原地待机 */
|
||||
this.clearCombatTarget(model);
|
||||
model.is_atking = false;
|
||||
this.moveEntity(view, -1, model.speed / 3);
|
||||
view.status_change("idle");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,69 +130,20 @@ export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
|
||||
private processCombatLogic(e: ecs.Entity, move: MonMoveComp, view: HeroViewComp, model: HeroAttrsComp, enemy: HeroViewComp) {
|
||||
const selfX = view.node.position.x;
|
||||
const enemyX = enemy.node.position.x;
|
||||
const dist = Math.abs(selfX - enemyX);
|
||||
const inRange = this.isEnemyInAttackRange(model, selfX, enemyX);
|
||||
|
||||
// 接触判定距离,只有接触英雄才停止移动
|
||||
const touchDistance = 120;
|
||||
const isTouching = dist <= touchDistance;
|
||||
|
||||
// 攻击判定
|
||||
// 攻击判定:怪物在固定位置,如果在攻击范围内则攻击,否则原地待机
|
||||
if (inRange) {
|
||||
model.is_atking = true;
|
||||
// 确保朝向敌人
|
||||
const dir = enemyX > selfX ? 1 : -1;
|
||||
view.scale = dir;
|
||||
} else {
|
||||
model.is_atking = false;
|
||||
}
|
||||
|
||||
// 移动判定:只有接触了英雄才停止移动,否则继续向英雄方向移动
|
||||
if (isTouching) {
|
||||
view.status_change("idle");
|
||||
} else {
|
||||
const dir = enemyX > selfX ? 1 : -1;
|
||||
this.moveEntity(view, dir, model.speed / 3);
|
||||
}
|
||||
}
|
||||
|
||||
private moveEntity(view: HeroViewComp, direction: number, speed: number) {
|
||||
const model = view.ent.get(HeroAttrsComp);
|
||||
const move = view.ent.get(MonMoveComp);
|
||||
if (!model || !move) return;
|
||||
|
||||
// 简化的边界限制(怪物主要往左走,英雄防线在左侧,-999999 代表左侧尽头)
|
||||
const moveMinX = -999999;
|
||||
const moveMaxX = 999999;
|
||||
|
||||
const currentX = view.node.position.x;
|
||||
const delta = speed * this.dt * direction;
|
||||
let newX = currentX + delta;
|
||||
|
||||
newX = Math.max(moveMinX, Math.min(moveMaxX, newX));
|
||||
if (Math.abs(newX - currentX) < 0.01) {
|
||||
view.status_change("idle");
|
||||
return;
|
||||
}
|
||||
|
||||
view.node.setPosition(newX, move.baseY, 0);
|
||||
move.direction = direction;
|
||||
|
||||
// 确保怪物的朝向表现,向左走 scale=-1,向右走 scale=1
|
||||
if (direction < 0) {
|
||||
view.scale = -1;
|
||||
} else if (direction > 0) {
|
||||
view.scale = 1;
|
||||
}
|
||||
|
||||
view.status_change("move");
|
||||
}
|
||||
|
||||
private resolveCombatRange(model: HeroAttrsComp, defaultMin: number, defaultMax: number): [number, number] {
|
||||
const minRange = model.getCachedMinSkillDistance();
|
||||
const maxRange = model.getCachedMaxSkillDistance();
|
||||
if (maxRange <= 0) return [defaultMin, defaultMax];
|
||||
const safeMin = Math.max(0, Math.min(minRange, maxRange - 20));
|
||||
return [safeMin, maxRange];
|
||||
}
|
||||
|
||||
private findNearestEnemy(entity: ecs.Entity): HeroViewComp | null {
|
||||
const currentView = entity.get(HeroViewComp);
|
||||
if (!currentView?.node) return null;
|
||||
|
||||
Reference in New Issue
Block a user