Files
heros/assets/script/game/common/ecs/position/BattleMoveSystem.ts

166 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
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);
}
}