diff --git a/assets/script/game/hero/HeroMove.ts b/assets/script/game/hero/HeroMove.ts deleted file mode 100644 index dc77c0a5..00000000 --- a/assets/script/game/hero/HeroMove.ts +++ /dev/null @@ -1,300 +0,0 @@ -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/GameSet"; -import { HType } from "../common/config/heroSet"; -import { Attrs } from "../common/config/HeroAttrs"; -import { SkillRange } from "../common/config/SkillSet"; - -/** 英雄移动组件 */ -@ecs.register('HeroMove') -export class HeroMoveComp 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('HeroMoveSystem') -export class HeroMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { - filter(): ecs.IMatcher { - return ecs.allOf(HeroMoveComp, HeroViewComp, HeroAttrsComp); - } - - update(e: ecs.Entity) { - // 1. 全局状态检查 - if (!smc.mission.play || smc.mission.pause) return; - // 如果开启了暂停怪物行动(通常用于四选一界面),玩家角色也应该停止移动 - if (smc.mission.stop_mon_action) return; - - const model = e.get(HeroAttrsComp); - const move = e.get(HeroMoveComp); - const view = e.get(HeroViewComp); - - // 只处理己方英雄且处于可移动状态 - if (model.fac !== FacSet.HERO) return; - if (!move.moving) return; - - // 2. 异常状态检查 (死亡/复活/眩晕/冰冻) - if (model.is_stop || model.is_dead || model.is_reviving || model.in_stun || model.in_frost) { - if (!model.is_reviving) view.status_change("idle"); - return; - } - - this.updateRenderOrder(e); - - // 3. 核心移动逻辑分发 - const nearestEnemy = this.findNearestEnemy(e); - - if (nearestEnemy) { - // 战斗状态:根据职业类型和rangeType执行智能战术 - this.processCombatLogic(e, move, view, model, nearestEnemy); - } else { - // 非战斗状态:回归阵型 - this.processReturnFormation(e, move, view, model); - model.is_atking = false; - } - } - - /** - * 战斗移动逻辑分发 - * 根据 rangeType 决定走位策略 - */ - private processCombatLogic(e: ecs.Entity, move: HeroMoveComp, view: HeroViewComp, model: HeroAttrsComp, enemy: HeroViewComp) { - // 优先使用 rangeType 判断,如果没有则回退到 type 判断 - let rangeType = model.rangeType; - - // 兼容性处理:如果数据未配置 rangeType,根据旧的职业类型推断 - if (rangeType === undefined) { - if (model.type === HType.warrior || model.type === HType.assassin) { - rangeType = SkillRange.Melee; - } else if (model.type === HType.remote) { - rangeType = SkillRange.Long; - } else { - rangeType = SkillRange.Mid; - } - } - - switch (rangeType) { - case SkillRange.Melee: - this.processMeleeLogic(e, move, view, model, enemy); - break; - case SkillRange.Mid: - this.processMidLogic(e, move, view, model, enemy); - break; - case SkillRange.Long: - this.processLongLogic(e, move, view, model, enemy); - break; - default: - this.processMidLogic(e, move, view, model, enemy); // 默认中程 - break; - } - } - - /** - * 近战逻辑 (Melee) - * 策略:无脑突进,贴脸输出 - * 范围:< 75 (攻击距离) - */ - private processMeleeLogic(e: ecs.Entity, move: HeroMoveComp, view: HeroViewComp, model: HeroAttrsComp, enemy: HeroViewComp) { - const currentX = view.node.position.x; - const enemyX = enemy.node.position.x; - const dist = Math.abs(currentX - enemyX); - const [minRange, maxRange] = this.resolveCombatRange(model, 0, 75); - - move.direction = enemyX > currentX ? 1 : -1; - - if (dist < minRange) { - this.performRetreat(view, move, model, currentX); - } else if (dist <= maxRange) { - view.status_change("idle"); - model.is_atking = true; - } else { - const speed = model.speed / 3; - this.moveEntity(view, move.direction, speed); - model.is_atking = false; - } - } - - /** - * 中程逻辑 (Mid) - * 策略:保持在中距离,灵活输出 - * 范围:120 - 360 - */ - private processMidLogic(e: ecs.Entity, move: HeroMoveComp, view: HeroViewComp, model: HeroAttrsComp, enemy: HeroViewComp) { - const currentX = view.node.position.x; - const enemyX = enemy.node.position.x; - const dist = Math.abs(currentX - enemyX); - - const [minRange, maxRange] = this.resolveCombatRange(model, 120, 360); - - move.direction = enemyX > currentX ? 1 : -1; - - if (dist < minRange) { - // 太近了,后撤 - this.performRetreat(view, move, model, currentX); - } else if (dist > maxRange) { - // 太远了,追击 - const speed = model.speed / 3; - this.moveEntity(view, move.direction, speed); - model.is_atking = false; - } else { - // 距离合适,站桩输出 - view.status_change("idle"); - model.is_atking = true; - } - } - - /** - * 远程逻辑 (Long) - * 策略:保持在远距离,最大化生存 - * 范围:360 - 720 - */ - private processLongLogic(e: ecs.Entity, move: HeroMoveComp, view: HeroViewComp, model: HeroAttrsComp, enemy: HeroViewComp) { - const currentX = view.node.position.x; - const enemyX = enemy.node.position.x; - const dist = Math.abs(currentX - enemyX); - - const [minRange, maxRange] = this.resolveCombatRange(model, 360, 720); - - move.direction = enemyX > currentX ? 1 : -1; - - if (dist < minRange) { - // 太近了,后撤 (远程单位对距离更敏感) - this.performRetreat(view, move, model, currentX); - } else if (dist > maxRange) { - // 太远了,追击 - const speed = model.speed / 3; - this.moveEntity(view, move.direction, speed); - model.is_atking = false; - } else { - // 距离合适,站桩输出 - view.status_change("idle"); - model.is_atking = true; - } - } - - /** 执行后撤逻辑 */ - private performRetreat(view: HeroViewComp, move: HeroMoveComp, model: HeroAttrsComp, currentX: number) { - const safeRetreatX = currentX - move.direction * 50; - if (safeRetreatX >= -300 && safeRetreatX <= 300) { - const retreatSpeed = (model.speed / 3) * 0.8; - this.moveEntity(view, -move.direction, retreatSpeed); - model.is_atking = false; - } else { - // 退无可退,被迫反击 - view.status_change("idle"); - model.is_atking = true; - } - } - - /** - * 回归阵型逻辑 - * 策略:无敌人时回到预设的 targetX - */ - private processReturnFormation(e: ecs.Entity, move: HeroMoveComp, view: HeroViewComp, model: HeroAttrsComp) { - const currentX = view.node.position.x; - let targetX = move.targetX; - - // 简单的防重叠偏移 - if (this.isPositionOccupied(targetX, e)) { - targetX -= 50; - } - - if (Math.abs(currentX - targetX) > 5) { - const dir = targetX > currentX ? 1 : -1; - const speed = model.speed / 3; - - // 修正朝向:回正 - move.direction = 1; - - this.moveEntity(view, dir, speed); - - // 防止过冲 - const newX = view.node.position.x; - if ((dir === 1 && newX > targetX) || (dir === -1 && newX < targetX)) { - view.node.setPosition(targetX, view.node.position.y, 0); - } - } else { - view.status_change("idle"); - move.direction = 1; // 归位后默认朝右 - } - } - - /** 通用移动执行 */ - private moveEntity(view: HeroViewComp, direction: number, speed: number) { - const delta = speed * this.dt * direction; - const newX = view.node.position.x + delta; - - // 地图边界限制 (硬限制) - if (newX >= -320 && newX <= 320) { - view.node.setPosition(newX, view.node.position.y, 0); - view.status_change("move"); - } else { - view.status_change("idle"); - } - } - - private resolveCombatRange(model: HeroAttrsComp, defaultMin: number, defaultMax: number): [number, number] { - const minRange = model.getCachedMinSkillDistance(); - const maxRange = model.getCachedMaxSkillDistance(); - if (maxRange <= 0) return [defaultMin, defaultMax]; - const safeMin = Math.max(0, Math.min(minRange, maxRange - 20)); - return [safeMin, maxRange]; - } - - // --- 辅助方法 --- - - private findNearestEnemy(entity: ecs.Entity): HeroViewComp | null { - const currentView = entity.get(HeroViewComp); - if (!currentView?.node) return null; - - const currentPos = currentView.node.position; - const myFac = entity.get(HeroAttrsComp).fac; - - let nearest: HeroViewComp | null = null; - let minDis = Infinity; - - // 优化查询:一次遍历 - ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => { - const m = e.get(HeroAttrsComp); - if (m.fac !== myFac && !m.is_dead) { - const v = e.get(HeroViewComp); - if (v?.node) { - const d = Math.abs(currentPos.x - v.node.position.x); - if (d < minDis) { - minDis = d; - nearest = v; - } - } - } - }); - return nearest; - } - - private isPositionOccupied(targetX: number, self: ecs.Entity): boolean { - const myFac = self.get(HeroAttrsComp).fac; - return ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => { - if (e === self) return false; - const m = e.get(HeroAttrsComp); - if (m.fac !== myFac || m.is_dead) return false; - - const v = e.get(HeroViewComp); - return Math.abs(v.node.position.x - targetX) < 30; - }); - } - - private updateRenderOrder(entity: ecs.Entity) { - // 渲染层级逻辑... - } -} diff --git a/assets/script/game/hero/MonMove.ts b/assets/script/game/hero/MonMove.ts deleted file mode 100644 index 1001ce94..00000000 --- a/assets/script/game/hero/MonMove.ts +++ /dev/null @@ -1,342 +0,0 @@ -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, IndexSet } from "../common/config/GameSet"; -import { Attrs } from "../common/config/HeroAttrs"; -import { HType } from "../common/config/heroSet"; -import { SkillRange } from "../common/config/SkillSet"; - -/** 怪物移动组件 */ -@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); - } - - update(e: ecs.Entity) { - // 1. 全局状态检查 - if (!smc.mission.play || 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); - - // 只处理怪物 - if (model.fac !== FacSet.MON) return; - if (!move.moving) return; - - // 2. 异常状态检查 (死亡/复活/眩晕/冰冻) - if (model.is_stop || model.is_dead || model.in_stun|| model.in_frost) { - view.status_change("idle"); - return; - } - - this.updateRenderOrder(e); - - // 检查是否需要y轴靠近 - this.checkAndSetTargetY(e); - - // 3. 核心移动逻辑分发 - const nearestEnemy = this.findNearestEnemy(e); - - if (nearestEnemy) { - // 战斗状态:根据职业类型和rangeType执行智能战术 - this.processCombatLogic(e, move, view, model, nearestEnemy); - } else { - // 非战斗状态:回归阵型 - move.targetY = 0; - this.processReturnFormation(e, move, view, model); - model.is_atking = false; - } - } - - /** - * 战斗移动逻辑分发 - * 根据 rangeType 决定走位策略 - */ - private processCombatLogic(e: ecs.Entity, move: MonMoveComp, view: HeroViewComp, model: HeroAttrsComp, enemy: HeroViewComp) { - // 优先使用 rangeType 判断,如果没有则回退到 type 判断 - let rangeType = model.rangeType; - - // 兼容性处理:如果数据未配置 rangeType,根据旧的职业类型推断 - if (rangeType === undefined) { - if (model.type === HType.warrior || model.type === HType.assassin) { - rangeType = SkillRange.Melee; - } else if (model.type === HType.remote) { - rangeType = SkillRange.Long; - } else { - rangeType = SkillRange.Mid; - } - } - - switch (rangeType) { - case SkillRange.Melee: - this.processMeleeLogic(e, move, view, model, enemy); - break; - case SkillRange.Mid: - this.processMidLogic(e, move, view, model, enemy); - break; - case SkillRange.Long: - this.processLongLogic(e, move, view, model, enemy); - break; - default: - this.processMidLogic(e, move, view, model, enemy); // 默认中程 - break; - } - } - - /** - * 近战逻辑 (Melee) - * 策略:无脑突进,贴脸输出 - * 范围:< 75 (攻击距离) - */ - private processMeleeLogic(e: ecs.Entity, move: MonMoveComp, view: HeroViewComp, model: HeroAttrsComp, enemy: HeroViewComp) { - const currentX = view.node.position.x; - const enemyX = enemy.node.position.x; - const dist = Math.abs(currentX - enemyX); - const [minRange, maxRange] = this.resolveCombatRange(model, 0, 75); - - move.direction = enemyX > currentX ? 1 : -1; - - if (dist < minRange) { - this.performRetreat(view, move, model, currentX); - } else if (dist <= maxRange) { - view.status_change("idle"); - model.is_atking = true; - } else { - const speed = model.speed / 3; - this.moveEntity(view, move.direction, speed); - model.is_atking = false; - } - } - - /** - * 中程逻辑 (Mid) - * 策略:保持在中距离,灵活输出 - * 范围:120 - 360 - */ - private processMidLogic(e: ecs.Entity, move: MonMoveComp, view: HeroViewComp, model: HeroAttrsComp, enemy: HeroViewComp) { - const currentX = view.node.position.x; - const enemyX = enemy.node.position.x; - const dist = Math.abs(currentX - enemyX); - - const [minRange, maxRange] = this.resolveCombatRange(model, 120, 360); - - move.direction = enemyX > currentX ? 1 : -1; - - if (dist < minRange) { - // 太近了,后撤 - this.performRetreat(view, move, model, currentX); - } else if (dist > maxRange) { - // 太远了,追击 - const speed = model.speed / 3; - this.moveEntity(view, move.direction, speed); - model.is_atking = false; - } else { - // 距离合适,站桩输出 - view.status_change("idle"); - model.is_atking = true; - } - } - - /** - * 远程逻辑 (Long) - * 策略:保持在远距离,最大化生存 - * 范围:360 - 720 - */ - private processLongLogic(e: ecs.Entity, move: MonMoveComp, view: HeroViewComp, model: HeroAttrsComp, enemy: HeroViewComp) { - const currentX = view.node.position.x; - const enemyX = enemy.node.position.x; - const dist = Math.abs(currentX - enemyX); - - const [minRange, maxRange] = this.resolveCombatRange(model, 360, 720); - - move.direction = enemyX > currentX ? 1 : -1; - - if (dist < minRange) { - // 太近了,后撤 (远程单位对距离更敏感) - this.performRetreat(view, move, model, currentX); - } else if (dist > maxRange) { - // 太远了,追击 - const speed = model.speed / 3; - this.moveEntity(view, move.direction, speed); - model.is_atking = false; - } else { - // 距离合适,站桩输出 - view.status_change("idle"); - model.is_atking = true; - } - } - - /** 执行后撤逻辑 */ - private performRetreat(view: HeroViewComp, move: MonMoveComp, model: HeroAttrsComp, currentX: number) { - const safeRetreatX = currentX - move.direction * 50; - if (safeRetreatX >= -300 && safeRetreatX <= 300) { - const retreatSpeed = (model.speed / 3) * 0.8; - this.moveEntity(view, -move.direction, retreatSpeed); - model.is_atking = false; - } else { - // 退无可退,被迫反击 - view.status_change("idle"); - model.is_atking = true; - } - } - - /** 回归阵型逻辑 */ - private processReturnFormation(e: ecs.Entity, move: MonMoveComp, view: HeroViewComp, model: HeroAttrsComp) { - const currentX = view.node.position.x; - const targetX = move.targetX; - - if (Math.abs(currentX - targetX) > 5) { - const dir = targetX > currentX ? 1 : -1; - const speed = model.speed / 3; - - move.direction = dir; - - this.moveEntity(view, dir, speed); - } else { - view.status_change("idle"); - } - } - - /** 通用移动执行 */ - private moveEntity(view: HeroViewComp, direction: number, speed: number) { - const delta = speed * this.dt * direction; - const newX = view.node.position.x + delta; - - // 处理Y轴移动 - const move = view.ent.get(MonMoveComp); - let newY = view.node.position.y; - if (move && move.targetY !== 0) { - const deltaY = speed * 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 (newX >= -320 && newX <= 320) { - view.node.setPosition(newX, newY, 0); - view.status_change("move"); - } else { - view.status_change("idle"); - } - } - - private resolveCombatRange(model: HeroAttrsComp, defaultMin: number, defaultMax: number): [number, number] { - const minRange = model.getCachedMinSkillDistance(); - const maxRange = model.getCachedMaxSkillDistance(); - if (maxRange <= 0) return [defaultMin, defaultMax]; - const safeMin = Math.max(0, Math.min(minRange, maxRange - 20)); - return [safeMin, maxRange]; - } - - /** 检查并设置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; - } - } - - private findNearestEnemy(entity: ecs.Entity): HeroViewComp | null { - const currentView = entity.get(HeroViewComp); - if (!currentView?.node) return null; - - const currentPos = currentView.node.position; - const myFac = entity.get(HeroAttrsComp).fac; - - let nearest: HeroViewComp | null = null; - let minDis = Infinity; - - ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => { - const m = e.get(HeroAttrsComp); - // 找对立阵营且存活的 - if (m.fac !== myFac && !m.is_dead) { - const v = e.get(HeroViewComp); - if (v?.node) { - const d = Math.abs(currentPos.x - v.node.position.x); - if (d < minDis) { - minDis = d; - nearest = v; - } - } - } - }); - return nearest; - } - - private updateRenderOrder(entity: ecs.Entity) { - // 🔥 移除渲染层级更新:各线路固定,后召唤的天然层级更高,无需动态调整 - } -}