feat(移动系统): 实现多线站位和防重叠机制
- 将移动边界配置从 min/max 改为 front/back 以支持双向移动逻辑 - 增加四条站位线(LINE1~LINE4)实现纵向分层站位 - 添加防重叠检测,防止同阵营单位位置冲突 - 调整游戏地平线高度和地图元素位置以适配新站位系统 - 禁用地图中多余的游戏对象以优化性能
This commit is contained in:
@@ -584,7 +584,7 @@
|
|||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": -295.746,
|
"y": -245.746,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"_lrot": {
|
"_lrot": {
|
||||||
@@ -856,7 +856,7 @@
|
|||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": -278.047,
|
"y": -228.047,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"_lrot": {
|
"_lrot": {
|
||||||
@@ -992,7 +992,7 @@
|
|||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": -282.963,
|
"y": -232.963,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"_lrot": {
|
"_lrot": {
|
||||||
@@ -1128,7 +1128,7 @@
|
|||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": -580.208,
|
"y": -530.208,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"_lrot": {
|
"_lrot": {
|
||||||
@@ -1264,7 +1264,7 @@
|
|||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": -320,
|
"y": -270,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"_lrot": {
|
"_lrot": {
|
||||||
@@ -1433,7 +1433,7 @@
|
|||||||
"__id__": 62
|
"__id__": 62
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": false,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 70
|
"__id__": 70
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export enum BoxSet {
|
|||||||
LETF_END = -420,
|
LETF_END = -420,
|
||||||
RIGHT_END = 420,
|
RIGHT_END = 420,
|
||||||
//游戏地平线
|
//游戏地平线
|
||||||
GAME_LINE = -215,
|
GAME_LINE = -165
|
||||||
//攻击距离
|
//攻击距离
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,26 +28,35 @@ export class MoveComp extends ecs.Comp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface MoveFacConfig {
|
interface MoveFacConfig {
|
||||||
moveMinX: number;
|
moveFrontX: number;
|
||||||
moveMaxX: number;
|
moveBackX: number;
|
||||||
retreatMinX: number;
|
retreatFrontX: number;
|
||||||
retreatMaxX: number;
|
retreatBackX: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@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 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> = {
|
private readonly facConfigs: Record<number, MoveFacConfig> = {
|
||||||
[FacSet.HERO]: {
|
[FacSet.HERO]: {
|
||||||
moveMinX: -320,
|
moveFrontX: 320,
|
||||||
moveMaxX: 320,
|
moveBackX: -320,
|
||||||
retreatMinX: -300,
|
retreatFrontX: 300,
|
||||||
retreatMaxX: 300,
|
retreatBackX: -300,
|
||||||
},
|
},
|
||||||
[FacSet.MON]: {
|
[FacSet.MON]: {
|
||||||
moveMinX: -320,
|
moveFrontX: -320,
|
||||||
moveMaxX: 320,
|
moveBackX: 320,
|
||||||
retreatMinX: -300,
|
retreatFrontX: -300,
|
||||||
retreatMaxX: 300,
|
retreatBackX: 300,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,6 +81,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.applyLineAndY(e, view, move, view.node.position.x);
|
||||||
this.updateRenderOrder(e);
|
this.updateRenderOrder(e);
|
||||||
const nearestEnemy = this.findNearestEnemy(e);
|
const nearestEnemy = this.findNearestEnemy(e);
|
||||||
if (nearestEnemy) {
|
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) {
|
private performRetreat(view: HeroViewComp, move: MoveComp, model: HeroAttrsComp, currentX: number) {
|
||||||
const cfg = this.facConfigs[model.fac] || this.facConfigs[FacSet.HERO];
|
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;
|
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;
|
const retreatSpeed = (model.speed / 3) * 0.8;
|
||||||
this.moveEntity(view, -move.direction, retreatSpeed);
|
this.moveEntity(view, -move.direction, retreatSpeed);
|
||||||
model.is_atking = false;
|
model.is_atking = false;
|
||||||
@@ -233,23 +245,67 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
|||||||
const move = view.ent.get(MoveComp);
|
const move = view.ent.get(MoveComp);
|
||||||
if (!model || !move) return;
|
if (!model || !move) return;
|
||||||
const cfg = this.facConfigs[model.fac] || this.facConfigs[FacSet.HERO];
|
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 currentX = view.node.position.x;
|
||||||
const delta = speed * this.dt * direction;
|
const delta = speed * this.dt * direction;
|
||||||
let newX = view.node.position.x + delta;
|
let newX = view.node.position.x + delta;
|
||||||
if (currentX < cfg.moveMinX && direction < 0) {
|
if (currentX < moveMinX && direction < 0) {
|
||||||
view.status_change("idle");
|
view.status_change("idle");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (currentX > cfg.moveMaxX && direction > 0) {
|
if (currentX > moveMaxX && direction > 0) {
|
||||||
view.status_change("idle");
|
view.status_change("idle");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
newX = Math.max(cfg.moveMinX, Math.min(cfg.moveMaxX, newX));
|
newX = Math.max(moveMinX, Math.min(moveMaxX, newX));
|
||||||
const newY = view.node.position.y;
|
const newY = this.applyLineAndY(view.ent, view, move, newX);
|
||||||
view.node.setPosition(newX, newY, 0);
|
view.node.setPosition(newX, newY, 0);
|
||||||
view.status_change("move");
|
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] {
|
private resolveCombatRange(model: HeroAttrsComp, defaultMin: number, defaultMax: number): [number, number] {
|
||||||
const minRange = model.getCachedMinSkillDistance();
|
const minRange = model.getCachedMinSkillDistance();
|
||||||
const maxRange = model.getCachedMaxSkillDistance();
|
const maxRange = model.getCachedMaxSkillDistance();
|
||||||
|
|||||||
Reference in New Issue
Block a user