feat(移动系统): 实现多线站位和防重叠机制
- 将移动边界配置从 min/max 改为 front/back 以支持双向移动逻辑 - 增加四条站位线(LINE1~LINE4)实现纵向分层站位 - 添加防重叠检测,防止同阵营单位位置冲突 - 调整游戏地平线高度和地图元素位置以适配新站位系统 - 禁用地图中多余的游戏对象以优化性能
This commit is contained in:
@@ -18,7 +18,7 @@ export enum BoxSet {
|
||||
LETF_END = -420,
|
||||
RIGHT_END = 420,
|
||||
//游戏地平线
|
||||
GAME_LINE = -215,
|
||||
GAME_LINE = -165
|
||||
//攻击距离
|
||||
}
|
||||
|
||||
|
||||
@@ -28,26 +28,35 @@ export class MoveComp extends ecs.Comp {
|
||||
}
|
||||
|
||||
interface MoveFacConfig {
|
||||
moveMinX: number;
|
||||
moveMaxX: number;
|
||||
retreatMinX: number;
|
||||
retreatMaxX: number;
|
||||
moveFrontX: number;
|
||||
moveBackX: number;
|
||||
retreatFrontX: number;
|
||||
retreatBackX: number;
|
||||
}
|
||||
|
||||
@ecs.register('MoveSystem')
|
||||
export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
||||
private readonly ySlots = [
|
||||
{ offset: 0, lineName: "LINE2" },
|
||||
{ offset: 5, lineName: "LINE1" },
|
||||
{ offset: -5, lineName: "LINE3" },
|
||||
{ offset: -10, lineName: "LINE4" },
|
||||
];
|
||||
private readonly samePointXThreshold = 12;
|
||||
private readonly samePointYThreshold = 3;
|
||||
|
||||
private readonly facConfigs: Record<number, MoveFacConfig> = {
|
||||
[FacSet.HERO]: {
|
||||
moveMinX: -320,
|
||||
moveMaxX: 320,
|
||||
retreatMinX: -300,
|
||||
retreatMaxX: 300,
|
||||
moveFrontX: 320,
|
||||
moveBackX: -320,
|
||||
retreatFrontX: 300,
|
||||
retreatBackX: -300,
|
||||
},
|
||||
[FacSet.MON]: {
|
||||
moveMinX: -320,
|
||||
moveMaxX: 320,
|
||||
retreatMinX: -300,
|
||||
retreatMaxX: 300,
|
||||
moveFrontX: -320,
|
||||
moveBackX: 320,
|
||||
retreatFrontX: -300,
|
||||
retreatBackX: 300,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -72,6 +81,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
return;
|
||||
}
|
||||
|
||||
this.applyLineAndY(e, view, move, view.node.position.x);
|
||||
this.updateRenderOrder(e);
|
||||
const nearestEnemy = this.findNearestEnemy(e);
|
||||
if (nearestEnemy) {
|
||||
@@ -177,8 +187,10 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
|
||||
private performRetreat(view: HeroViewComp, move: MoveComp, model: HeroAttrsComp, currentX: number) {
|
||||
const cfg = this.facConfigs[model.fac] || this.facConfigs[FacSet.HERO];
|
||||
const retreatMinX = Math.min(cfg.retreatBackX, cfg.retreatFrontX);
|
||||
const retreatMaxX = Math.max(cfg.retreatBackX, cfg.retreatFrontX);
|
||||
const safeRetreatX = currentX - move.direction * 50;
|
||||
if (safeRetreatX >= cfg.retreatMinX && safeRetreatX <= cfg.retreatMaxX) {
|
||||
if (safeRetreatX >= retreatMinX && safeRetreatX <= retreatMaxX) {
|
||||
const retreatSpeed = (model.speed / 3) * 0.8;
|
||||
this.moveEntity(view, -move.direction, retreatSpeed);
|
||||
model.is_atking = false;
|
||||
@@ -233,23 +245,67 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
const move = view.ent.get(MoveComp);
|
||||
if (!model || !move) return;
|
||||
const cfg = this.facConfigs[model.fac] || this.facConfigs[FacSet.HERO];
|
||||
const moveMinX = Math.min(cfg.moveBackX, cfg.moveFrontX);
|
||||
const moveMaxX = Math.max(cfg.moveBackX, cfg.moveFrontX);
|
||||
const currentX = view.node.position.x;
|
||||
const delta = speed * this.dt * direction;
|
||||
let newX = view.node.position.x + delta;
|
||||
if (currentX < cfg.moveMinX && direction < 0) {
|
||||
if (currentX < moveMinX && direction < 0) {
|
||||
view.status_change("idle");
|
||||
return;
|
||||
}
|
||||
if (currentX > cfg.moveMaxX && direction > 0) {
|
||||
if (currentX > moveMaxX && direction > 0) {
|
||||
view.status_change("idle");
|
||||
return;
|
||||
}
|
||||
newX = Math.max(cfg.moveMinX, Math.min(cfg.moveMaxX, newX));
|
||||
const newY = view.node.position.y;
|
||||
newX = Math.max(moveMinX, Math.min(moveMaxX, newX));
|
||||
const newY = this.applyLineAndY(view.ent, view, move, newX);
|
||||
view.node.setPosition(newX, newY, 0);
|
||||
view.status_change("move");
|
||||
}
|
||||
|
||||
private applyLineAndY(entity: ecs.Entity, view: HeroViewComp, move: MoveComp, x: number): number {
|
||||
if (!view.node) return 0;
|
||||
const baseY = move.baseY;
|
||||
for (const slot of this.ySlots) {
|
||||
const y = baseY + slot.offset;
|
||||
if (!this.hasTeammateAtPoint(entity, x, y)) {
|
||||
const lineNode = this.getLineNode(slot.lineName);
|
||||
if (lineNode && view.node.parent !== lineNode) {
|
||||
view.node.parent = lineNode;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
}
|
||||
const fallback = this.ySlots[0];
|
||||
const fallbackNode = this.getLineNode(fallback.lineName);
|
||||
if (fallbackNode && view.node.parent !== fallbackNode) {
|
||||
view.node.parent = fallbackNode;
|
||||
}
|
||||
return baseY + fallback.offset;
|
||||
}
|
||||
|
||||
private getLineNode(lineName: string) {
|
||||
const scene = smc.map?.MapView?.scene;
|
||||
const layerRoot = scene?.entityLayer?.node;
|
||||
if (!layerRoot) return null;
|
||||
return layerRoot.getChildByName(lineName);
|
||||
}
|
||||
|
||||
private hasTeammateAtPoint(self: ecs.Entity, x: number, y: number): boolean {
|
||||
const myAttrs = self.get(HeroAttrsComp);
|
||||
if (!myAttrs) return false;
|
||||
return ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => {
|
||||
if (e === self) return false;
|
||||
const attrs = e.get(HeroAttrsComp);
|
||||
if (!attrs || attrs.fac !== myAttrs.fac || attrs.is_dead) return false;
|
||||
const view = e.get(HeroViewComp);
|
||||
if (!view || !view.node) return false;
|
||||
return Math.abs(view.node.position.x - x) <= this.samePointXThreshold
|
||||
&& Math.abs(view.node.position.y - y) <= this.samePointYThreshold;
|
||||
});
|
||||
}
|
||||
|
||||
private resolveCombatRange(model: HeroAttrsComp, defaultMin: number, defaultMax: number): [number, number] {
|
||||
const minRange = model.getCachedMinSkillDistance();
|
||||
const maxRange = model.getCachedMaxSkillDistance();
|
||||
|
||||
Reference in New Issue
Block a user