import { HeroViewComp } from "../../../hero/HeroViewComp"; import { BattleMoveComp } from "./BattleMoveComp"; import { ecs } from "../../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { smc } from "../../SingletonModuleComp"; import { BoxSet } from "../../config/BoxSet"; @ecs.register('BattleMoveSystem') export class BattleMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { filter(): ecs.IMatcher { return ecs.allOf(BattleMoveComp, HeroViewComp); } update(e: ecs.Entity) { if(!smc.mission.play||smc.mission.pause) return const move = e.get(BattleMoveComp); const view = e.get(HeroViewComp); if (!move.moving) return; // 检测攻击范围内是否有敌人 // 检测友方碰撞和敌方攻击范围 // const alliesStop = this.checkAlliesInProximity(e); const enemiesStop = this.checkEnemiesInRange(e, view.dis); const shouldStop = enemiesStop; view.is_atking = shouldStop; // 更新渲染层级 this.updateRenderOrder(e); // 同步状态 if (!shouldStop&&view.fac==1) { if(view.is_stop||view.is_dead) return //停止移动或者死亡不移动 // 计算移动量 const delta = (view.speed/3) * this.dt * move.direction; const newX = view.node.position.x + delta; view.status_change("move") // 新增墓地位置判断,如果已经在墓地则不再移动 if (view.node.position.x === -1000 || view.node.position.x === 1000) { return; } // 限制移动范围 if (this.validatePosition(newX, move)) { view.node.setPosition(newX, view.node.position.y, 0); } } else{ view.status_change("idle") } // console.log(`[${view.hero_name}] 类型:${view.type} 是否停止:${shouldStop} 方向:${move.direction} 位置:${view.node.position.x.toFixed(1)}`); } /** 验证目标位置有效性 */ private validatePosition(newX: number, move: BattleMoveComp): boolean { // 我方不能超过右边界,敌方不能超过左边界 return move.direction === 1 ? newX <= move.targetX : newX >= move.targetX; } /** 检测友方单位碰撞 */ private checkAlliesInProximity(entity: ecs.Entity): boolean { const current = entity.get(HeroViewComp); const currentPos = current.node.position; const SAFE_DISTANCE = 30; // 安全距离 // 查找同阵营同类型的所有友军(包括当前单位) const allAllies = ecs.query(ecs.allOf(HeroViewComp)).filter(e => { const other = e.get(HeroViewComp); return (e === entity || ( other.fac === current.fac && other.type === current.type )); }); // 按uuid从小到大排序 const sortedAllies = allAllies.sort((a, b) => { return a.get(HeroViewComp).hero_uuid - b.get(HeroViewComp).hero_uuid; }); // 找到当前单位在排序中的位置 const currentIndex = sortedAllies.findIndex(e => e === entity); // 设置渲染顺序 if (current.is_boss) { // boss显示在最上层 current.node.setSiblingIndex(999); } else { // 非boss单位,uuid越小的显示在下层(索引越小) current.node.setSiblingIndex(currentIndex); } // 如果是uuid最小的单位,直接移动 if (currentIndex === 0) { current.is_stop_temp = false; return false; } // 获取前一个单位(uuid比当前小的最近单位) // const prevUnit = sortedAllies[currentIndex - 1]; // const prevView = prevUnit.get(HeroViewComp); // const distToPrev = Math.abs(currentPos.x - prevView.node.position.x); // 如果与前一个单位距离小于安全距离,则停止 // if (distToPrev < SAFE_DISTANCE) { // current.is_stop_temp = true; // return true; // } // 如果与前一个单位距离大于安全距离,则移动 current.is_stop_temp = false; return false; } /** 检测攻击范围内敌人 */ private checkEnemiesInRange(entity: ecs.Entity, range: number): boolean { const currentPos = entity.get(HeroViewComp).node.position; const team = entity.get(HeroViewComp).fac; const view = entity.get(HeroViewComp); // const isMelee = view.type === 0; const isMelee = false; return ecs.query(ecs.allOf(HeroViewComp)).some(e => { const view = e.get(HeroViewComp); const distance = Math.abs(currentPos.x - view.node.position.x); if (isMelee) { // 近战需要满足:在攻击范围内且距离<=75才停止 const inAttackRange = distance <= range; const closeEnough = distance <= 75; // 近战停止距离 return view.fac !== team && inAttackRange && closeEnough; } else { // 远程/辅助:在攻击范围内即停止 return view.fac !== team && distance <= range; } }); } /** 更新渲染层级 */ private updateRenderOrder(entity: ecs.Entity) { const current = entity.get(HeroViewComp); // 查找所有单位 const allUnits = ecs.query(ecs.allOf(HeroViewComp)).filter(e => { const other = e.get(HeroViewComp); return other.fac === current.fac; // 按阵营分组 }); // 按y坐标从大到小排序(y坐标越小显示在上层) const sortedUnits = allUnits.sort((a, b) => { const posA = a.get(HeroViewComp).node.position.y; const posB = b.get(HeroViewComp).node.position.y; return posB - posA; // 修改排序顺序 }); // 设置渲染顺序 // 根据y坐标设置层级,y坐标越小的显示在上层 const index = sortedUnits.findIndex(e => e === entity); current.node.setSiblingIndex(index); } }