Files
pixelheros/assets/script/game/hero/MonMove.ts
walkpan 01431f1d53 fix: 调整英雄刘邦属性和技能范围,优化移动边界逻辑
- 将刘邦的攻击距离从100增加到120
- 调整战士移动边界从±420到±280
- 修改怪物移动逻辑,x>280时允许移动攻击
- 关闭部分prefab的_active状态
- 增加技能5000和6001-6002的攻击距离
2026-01-04 23:19:24 +08:00

261 lines
9.5 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 { HeroSkillsComp } from "./HeroSkills";
import { smc } from "../common/SingletonModuleComp";
import { FacSet, IndexSet } from "../common/config/GameSet";
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;
/** 线路标识0=一线(y=120)1=二线(y=80) */
lane: number = 0;
/** 生成顺序:用于同线路内的层级排序,数值越大越晚生成,层级越前 */
spawnOrder: number = 0;
/** 目标y坐标 */
targetY: number = 0;
reset() {
this.direction = 1;
this.targetX = 0;
this.moving = true;
this.lane = 0;
this.spawnOrder = 0;
this.targetY = 0;
}
}
/** 怪物移动系统 - 专门处理怪物的移动逻辑 */
@ecs.register('MonMoveSystem')
export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
filter(): ecs.IMatcher {
return ecs.allOf(MonMoveComp, HeroViewComp, HeroAttrsComp, HeroSkillsComp);
}
update(e: ecs.Entity) {
if (!smc.mission.play ) return;
if(smc.mission.pause) return
const view = e.get(HeroViewComp);
// 如果英雄死亡停止怪物行动标志为true则停止怪物移动
if (smc.mission.stop_mon_action) {
view.status_change("idle");
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 shouldStopInFace = this.checkEnemiesInFace(e);
const shouldStopAtMinRange = this.shouldStopAtMinSkillRange(e);
let shouldStop = shouldStopInFace || shouldStopAtMinRange;
model.is_atking = this.checkEnemiesInSkillRange(e);
// x > 280 强制移动,允许攻击
if (view.node.position.x > 280) {
shouldStop = false;
}
// 🔥 移除渲染层级更新:各线路固定,后召唤的天然层级更高,无需动态调整
if (!shouldStop) {
if (model.is_stop || model.is_dead || model.isStun() || model.isFrost()) {
view.status_change("idle");
return;
}
// 检查是否需要y轴靠近
this.checkAndSetTargetY(e);
// 怪物移动逻辑同时向目标x和y方向移动
const deltaX = (model.Attrs[Attrs.SPEED]/3) * this.dt * move.direction;
const newX = view.node.position.x + deltaX;
let newY = view.node.position.y;
if (move.targetY !== 0) {
const deltaY = (model.Attrs[Attrs.SPEED]/3) * this.dt * Math.sign(move.targetY - newY);
newY = newY + deltaY;
if (Math.abs(newY - move.targetY) < Math.abs(deltaY)) {
newY = move.targetY;
move.targetY = 0;
}
}
// 限制移动范围
if (this.validatePosition(newX, move)) {
view.status_change("move");
view.node.setPosition(newX, newY, 0);
} else {
view.status_change("idle");
move.moving = false;
}
} else {
view.status_change("idle");
}
}
/** 验证目标位置有效性 */
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 checkEnemiesInSkillRange(entity: ecs.Entity): boolean {
const currentView = entity.get(HeroViewComp);
const heroAttrs = entity.get(HeroAttrsComp);
if (!currentView || !currentView.node || !heroAttrs) return false;
const currentPos = currentView.node.position;
const team = heroAttrs.fac;
// 使用缓存的最远技能攻击距离判断攻击时机
const maxSkillDistance = heroAttrs.getCachedMaxSkillDistance();
if (maxSkillDistance === 0) return false;
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 <= maxSkillDistance) {
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 shouldStopAtMinSkillRange(entity: ecs.Entity): boolean {
const currentView = entity.get(HeroViewComp);
const heroAttrs = entity.get(HeroAttrsComp);
if (!currentView || !currentView.node || !heroAttrs) return false;
const currentPos = currentView.node.position;
const team = heroAttrs.fac;
// 使用缓存的最近技能攻击距离
const minSkillDistance = heroAttrs.getCachedMinSkillDistance();
if (minSkillDistance === 0) return false;
// 检查是否有敌人在最近技能距离内
return 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) {
return distance <= minSkillDistance;
}
return false;
});
}
/** 检查并设置y轴目标位置 */
private checkAndSetTargetY(entity: ecs.Entity): void {
const move = entity.get(MonMoveComp);
const currentView = entity.get(HeroViewComp);
const heroAttrs = entity.get(HeroAttrsComp);
if (!currentView || !currentView.node || !heroAttrs) return;
if (move.targetY !== 0) return;
const currentPos = currentView.node.position;
const team = heroAttrs.fac;
let nearestHero: ecs.Entity | null = null;
let nearestDist = Infinity;
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => {
const model = e.get(HeroAttrsComp);
const view = e.get(HeroViewComp);
if (!view || !view.node) return;
if (model.fac === team || model.is_dead) return;
const dist = Math.abs(currentPos.x - view.node.position.x);
if (dist < nearestDist) {
nearestDist = dist;
nearestHero = e;
}
});
if (!nearestHero || nearestDist > 100) return;
const heroView = nearestHero.get(HeroViewComp);
if (!heroView || !heroView.node) return;
const heroY = heroView.node.position.y;
const yDist = Math.abs(currentPos.y - heroY);
if (yDist > 50) {
const direction = heroY > currentPos.y ? 1 : -1;
move.targetY = heroY + direction * 50;
}
}
}