Files
heros/assets/script/game/hero/MonMove.ts
panw 40e0086be3 refactor(hero): 移除SkillConComp并添加ECS系统注册装饰器
- 删除废弃的SkillConComp组件及其meta文件
- 为HeroAtkSystem、HeroAttrSystem等系统添加@ecs.register装饰器
- 在生命周期系统中添加空安全检查
- 移除SkillConComp相关引用及调试日志
- 在移动系统中添加节点有效性检查
2025-10-30 16:31:44 +08:00

164 lines
6.1 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 { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { HeroViewComp } from "./HeroViewComp";
import { HeroAttrsComp } from "./HeroAttrsComp";
import { smc } from "../common/SingletonModuleComp";
import { FacSet } from "../common/config/BoxSet";
import { Attrs } from "../common/config/HeroAttrs";
/** 怪物移动组件 */
@ecs.register('MonMove')
export class MonMoveComp extends ecs.Comp {
/** 移动方向1向右-1向左 */
direction: number = 1;
/** 目标x坐标 */
targetX: number = 0;
/** 是否处于移动状态 */
moving: boolean = true;
reset() {
this.direction = 1;
this.targetX = 0;
this.moving = true;
}
}
/** 怪物移动系统 - 专门处理怪物的移动逻辑 */
@ecs.register('MonMoveSystem')
export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
filter(): ecs.IMatcher {
return ecs.allOf(MonMoveComp, HeroViewComp, HeroAttrsComp);
}
update(e: ecs.Entity) {
if (!smc.mission.play || smc.mission.pause) return;
const move = e.get(MonMoveComp);
const model = e.get(HeroAttrsComp);
const view = e.get(HeroViewComp);
// 只处理怪物
if (model.fac !== FacSet.MON) return;
if (!move.moving) return;
const shouldStop = this.checkEnemiesInFace(e);
model.is_atking = this.checkEnemiesInRange(e, model.Attrs[Attrs.DIS]);
// 更新渲染层级
this.updateRenderOrder(e);
if (!shouldStop) {
if (model.is_stop || model.is_dead || model.isStun() || model.isFrost()) {
view.status_change("idle");
return;
}
// 新增墓地位置判断,如果已经在墓地则不再移动
if (view.node.position.x === -1000 || view.node.position.x === 1000) {
view.status_change("idle");
return;
}
// 怪物简单移动逻辑:向目标方向移动
const delta = (model.Attrs[Attrs.SPEED]/3) * this.dt * move.direction;
const newX = view.node.position.x + delta;
// 限制移动范围
if (this.validatePosition(newX, move)) {
view.status_change("move");
view.node.setPosition(newX, view.node.position.y, 0);
} else {
// 当达到目标位置边界时也切换为idle状态
view.status_change("idle");
// 达到边界是永久停止设置moving为false
move.moving = false;
}
} else {
view.status_change("idle");
// 因为敌人在面前而暂时停止不设置moving为false保持检查状态
}
}
/** 验证目标位置有效性 */
private validatePosition(newX: number, move: MonMoveComp): boolean {
// 我方不能超过右边界,敌方不能超过左边界
return move.direction === 1 ?
newX <= move.targetX :
newX >= move.targetX;
}
/** 检测攻击范围内敌人 */
private checkEnemiesInRange(entity: ecs.Entity, range: number): boolean {
const currentView = entity.get(HeroViewComp);
if (!currentView || !currentView.node) return false;
const currentPos = currentView.node.position;
const team = entity.get(HeroAttrsComp).fac;
let found = false;
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => {
const model = e.get(HeroAttrsComp);
const view = e.get(HeroViewComp);
if (!view || !view.node) return false;
const distance = Math.abs(currentPos.x - view.node.position.x);
if (model.fac !== team && !model.is_dead) {
if (distance <= range) {
found = true;
return true;
}
}
});
return found;
}
/** 检测面前是否有敌人 */
private checkEnemiesInFace(entity: ecs.Entity): boolean {
const currentView = entity.get(HeroViewComp);
if (!currentView || !currentView.node) return false;
const currentPos = currentView.node.position;
const team = entity.get(HeroAttrsComp).fac;
let found = false;
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => {
const model = e.get(HeroAttrsComp);
const view = e.get(HeroViewComp);
if (!view || !view.node) return false;
const distance = Math.abs(currentPos.x - view.node.position.x);
if (model.fac !== team && !model.is_dead) {
if (distance <= 75) {
found = true;
return true;
}
}
});
return found;
}
/** 更新渲染层级 */
private updateRenderOrder(entity: ecs.Entity) {
const currentView = entity.get(HeroViewComp);
const currentModel = entity.get(HeroAttrsComp);
// 查找所有怪物单位
const allUnits = ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp))
.filter(e => {
const otherModel = e.get(HeroAttrsComp);
return otherModel.fac === currentModel.fac; // 按阵营分组
})
.map(e => e);
// 按x坐标排序x坐标越大越前面的显示在上层
const sortedUnits = allUnits.sort((a, b) => {
const viewA = a.get(HeroViewComp);
const viewB = b.get(HeroViewComp);
if (!viewA || !viewA.node || !viewB || !viewB.node) return 0;
const posA = viewA.node.position.x;
const posB = viewB.node.position.x;
return posA - posB; // x坐标从小到大排序
});
// 设置渲染顺序x坐标越大的显示在上层index越大层级越高
sortedUnits.forEach((unit, index) => {
const model = unit.get(HeroViewComp);
model.node.setSiblingIndex(index); // 直接使用indexx坐标大的index大层级高
});
}
}