diff --git a/assets/script/Main.ts b/assets/script/Main.ts index 5e1f5ade..0ab6001f 100644 --- a/assets/script/Main.ts +++ b/assets/script/Main.ts @@ -6,9 +6,6 @@ import { ecs } from '../../extensions/oops-plugin-framework/assets/libs/ecs/ECS' import { UIConfigData } from './game/common/config/GameUIConfig'; import { smc } from './game/common/SingletonModuleComp'; import { Initialize } from './game/initialize/Initialize'; -import { EcsPositionSystem } from './game/common/ecs/position/EcsPositionSystem'; -import { WxCloudApi } from './game/wx_clound_client_api/WxCloudApi'; -// import { WxCloudApi } from './game/wx_clound_client_api/WxCloudApi'; const { ccclass, property } = _decorator; @@ -34,8 +31,6 @@ export class Main extends Root { protected async initEcsSystem() { // oops.ecs.add(new EcsPositionSystem()); - // oops.ecs.add(new EcsRoleSystem()); - // oops.ecs.add(new EcsInitializeSystem()); } } \ No newline at end of file diff --git a/assets/script/game/common/ecs/position/BattleMoveComp.ts b/assets/script/game/common/ecs/position/BattleMoveComp.ts deleted file mode 100644 index 5759af08..00000000 --- a/assets/script/game/common/ecs/position/BattleMoveComp.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ecs } from "../../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; -@ecs.register('BattleMove') -export class BattleMoveComp 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; - } -} \ No newline at end of file diff --git a/assets/script/game/common/ecs/position/BattleMoveSystem.ts b/assets/script/game/common/ecs/position/BattleMoveSystem.ts deleted file mode 100644 index 19f42664..00000000 --- a/assets/script/game/common/ecs/position/BattleMoveSystem.ts +++ /dev/null @@ -1,274 +0,0 @@ -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 { FacSet } from "../../config/BoxSet"; -import { HType } from "../../config/heroSet"; -import { Attrs } from "../../config/HeroAttrs"; -import { HeroAttrsComp } from "../../../hero/HeroAttrsComp"; - -@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 model = e.get(HeroAttrsComp); - const view = e.get(HeroViewComp); - - 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.fac==1){ - 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; - } - // 英雄阵营特殊逻辑:根据职业区分行为 - if (model.fac == FacSet.HERO) { - const hasEnemies = this.checkEnemiesExist(e); - const isWarrior = model.type === HType.warrior; - - // 战士职业:有敌人就向敌人前进 - if (isWarrior && hasEnemies) { - const nearestEnemy = this.findNearestEnemy(e); - if (nearestEnemy) { - const enemyX = nearestEnemy.node.position.x; - const currentX = view.node.position.x; - - // 根据敌人位置调整移动方向和朝向 - if (enemyX > currentX) { - move.direction = 1; // 向右移动 - view.node.setScale(1, 1, 1); // 面向右侧 - view.node.getChildByName("top").setScale(1, 1, 1); // 面向右侧 - } else { - move.direction = -1; // 向左移动 - view.node.setScale(-1, 1, 1); // 面向左侧 - view.node.getChildByName("top").setScale(-1, 1, 1); // 面向左侧 - } - - // 继续向敌人方向移动 - const delta = (model.Attrs[Attrs.SPEED]/3) * this.dt * move.direction; - const newX = view.node.position.x + delta; - - // 对于战士,允许更自由的移动范围 - if (newX >= -420 && newX <= 420) { // 使用地图边界 - view.status_change("move"); - view.node.setPosition(newX, view.node.position.y, 0); - } else { - view.status_change("idle"); - } - } - return; - } - - // 其他职业或战士无敌人时:回到预定点 - const currentX = view.node.position.x; - let finalTargetX = move.targetX; - - // 检查预定点是否已被占用 - if (this.isPositionOccupied(finalTargetX, e)) { - finalTargetX = move.targetX - 50; // 往前50的位置 - } - - // 如果不在目标位置,移动到目标位置 - if (Math.abs(currentX - finalTargetX) > 1) { - // 确定移动方向 - const direction = currentX > finalTargetX ? -1 : 1; - const delta = (model.Attrs[Attrs.SPEED]/3) * this.dt * direction; - const newX = view.node.position.x + delta; - - // 设置朝向 - if (direction === 1) { - view.node.setScale(1, 1, 1); // 面向右侧 - view.node.getChildByName("top").setScale(1, 1, 1); // 面向右侧 - } else { - view.node.setScale(-1, 1, 1); // 面向左侧 - view.node.getChildByName("top").setScale(-1, 1, 1); // 面向左侧 - } - - // 确保不会超过目标位置 - if (direction === 1 && newX > finalTargetX) { - view.node.setPosition(finalTargetX, view.node.position.y, 0); - } else if (direction === -1 && newX < finalTargetX) { - view.node.setPosition(finalTargetX, view.node.position.y, 0); - } else { - view.node.setPosition(newX, view.node.position.y, 0); - } - view.status_change("move"); - } else { - view.status_change("idle"); - // 到达目标位置后,面向右侧(敌人方向) - move.direction = 1; - view.node.setScale(1, 1, 1); // 面向右侧 - view.node.getChildByName("top").setScale(1, 1, 1); // 面向右侧 - } - 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,保持检查状态 - } - - // console.log(`[${model.hero_name}] 类型:${model.type} 是否停止:${shouldStop} 方向:${move.direction} 位置:${model.node.position.x.toFixed(1)}`); - } - - /** 检查是否存在敌人 */ - private checkEnemiesExist(entity: ecs.Entity): boolean { - const team = entity.get(HeroAttrsComp).fac; - let hasEnemies = false; - ecs.query(ecs.allOf(HeroAttrsComp)).some(e => { - const model = e.get(HeroAttrsComp); - if (model.fac !== team && !model.is_dead) { - hasEnemies = true; - return true; - } - }); - return hasEnemies; - } - - /** 找到最近的敌人 */ - private findNearestEnemy(entity: ecs.Entity): HeroViewComp | null { - const currentPos = entity.get(HeroViewComp).node.position; - const team = entity.get(HeroAttrsComp).fac; - let nearestEnemy: HeroAttrsComp | null = null; - let minDistance = Infinity; - - ecs.query(ecs.allOf(HeroAttrsComp)).forEach(e => { - const model = e.get(HeroAttrsComp); - const view = e.get(HeroViewComp); - if (model.fac !== team && !model.is_dead) { - const distance = Math.abs(currentPos.x - view.node.position.x); - if (distance < minDistance) { - minDistance = distance; - nearestEnemy = model; - } - } - }); - - return nearestEnemy; - } - - /** 验证目标位置有效性 */ - private validatePosition(newX: number, move: BattleMoveComp): boolean { - // 我方不能超过右边界,敌方不能超过左边界 - return move.direction === 1 ? - newX <= move.targetX : - newX >= move.targetX; - } - - /** 检测是否在墓地 */ - private checkInGrave(entity: ecs.Entity): boolean { - const model = entity.get(HeroViewComp); - return model.node.position.x === -1000 || model.node.position.x === 1000; - } - - /** 检测攻击范围内敌人 */ - private checkEnemiesInRange(entity: ecs.Entity, range: number): boolean { - const currentPos = entity.get(HeroViewComp).node.position; - const team = entity.get(HeroViewComp).fac; - let found = false; - ecs.query(ecs.allOf(HeroViewComp)).some(e => { - const model = e.get(HeroViewComp); - const distance = Math.abs(currentPos.x - model.node.position.x); - if (model.fac !== team) { - if (distance <= range) { - found = true; - return true; - } - } - }); - return found; - } - - private checkEnemiesInFace(entity: ecs.Entity): boolean { - const currentPos = entity.get(HeroViewComp).node.position; - const team = entity.get(HeroViewComp).fac; - let found = false; - ecs.query(ecs.allOf(HeroViewComp)).some(e => { - const model = e.get(HeroViewComp); - const distance = Math.abs(currentPos.x - model.node.position.x); - if (model.fac !== team) { - if (distance <= 75) { - found = true; - return true; - } - } - }); - return found; - } - /** 更新渲染层级 */ - 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; // 按阵营分组 - }) - .map(e => e); - - // 按x坐标排序:x坐标越大(越前面)的显示在上层 - const sortedUnits = allUnits.sort((a, b) => { - const posA = a.get(HeroViewComp).node.position.x; - const posB = b.get(HeroViewComp).node.position.x; - return posA - posB; // x坐标从小到大排序 - }); - - // 设置渲染顺序:x坐标越大的显示在上层(index越大,层级越高) - sortedUnits.forEach((unit, index) => { - const model = unit.get(HeroViewComp); - model.node.setSiblingIndex(index); // 直接使用index,x坐标大的index大,层级高 - }); - } - - /** 检查指定位置是否已被占用 */ - private isPositionOccupied(targetX: number, currentEntity: ecs.Entity): boolean { - const currentView = currentEntity.get(HeroViewComp); - const occupationRange = 30; // 定义占用范围为30像素 - - return ecs.query(ecs.allOf(HeroViewComp)).some(e => { - if (e === currentEntity) return false; // 排除自己 - - const model = e.get(HeroViewComp); - if (model.fac !== currentView.fac) return false; // 只检查同阵营 - if (model.is_dead) return false; // 排除死亡单位 - - const distance = Math.abs(model.node.position.x - targetX); - return distance < occupationRange; // 如果距离小于占用范围,认为被占用 - }); - } -} diff --git a/assets/script/game/common/ecs/position/BattleMoveSystem.ts.meta b/assets/script/game/common/ecs/position/BattleMoveSystem.ts.meta deleted file mode 100644 index 8ff1ffcb..00000000 --- a/assets/script/game/common/ecs/position/BattleMoveSystem.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "4.0.24", - "importer": "typescript", - "imported": true, - "uuid": "9f62614b-42c3-4f21-a3d6-68c9190082e8", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/assets/script/game/common/ecs/position/EcsPositionSystem.ts b/assets/script/game/common/ecs/position/EcsPositionSystem.ts deleted file mode 100644 index 26b48fc5..00000000 --- a/assets/script/game/common/ecs/position/EcsPositionSystem.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ecs } from "../../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; -import { BattleMoveSystem } from "./BattleMoveSystem"; -export class EcsPositionSystem extends ecs.System { - constructor() { - super(); - // this.add(new BattleMoveSystem()); - } -} diff --git a/assets/script/game/hero/Hero.ts b/assets/script/game/hero/Hero.ts index 84a6ce2b..0b474468 100644 --- a/assets/script/game/hero/Hero.ts +++ b/assets/script/game/hero/Hero.ts @@ -6,12 +6,12 @@ import { HeroAttrsComp } from "./HeroAttrsComp"; import { HeroViewComp } from "./HeroViewComp"; import { BoxSet, FacSet } from "../common/config/BoxSet"; import { HeroInfo, HeroPos, HType } from "../common/config/heroSet"; -import { BattleMoveComp } from "../common/ecs/position/BattleMoveComp"; import { GameEvent } from "../common/config/GameEvent"; import { SkillSet } from "../common/config/SkillSet"; import { time } from "console"; import { getNeAttrs, getAttrs ,Attrs} from "../common/config/HeroAttrs"; import { HeroSkillsComp } from "./HeroSkills"; +import { HeroMoveComp } from "./HeroMove"; /** 角色实体 */ @ecs.register(`Hero`) @@ -19,10 +19,10 @@ export class Hero extends ecs.Entity { HeroModel!: HeroAttrsComp; HeroSkills!: HeroSkillsComp; View!: HeroViewComp; - BattleMove!: BattleMoveComp; + HeroMove!: HeroMoveComp; protected init() { this.addComponents( - BattleMoveComp, + HeroMoveComp, HeroAttrsComp, HeroSkillsComp, ); @@ -95,7 +95,7 @@ export class Hero extends ecs.Entity { this.add(hv); oops.message.dispatchEvent(GameEvent.MasterCalled,{uuid:uuid}) - const move = this.get(BattleMoveComp); + const move = this.get(HeroMoveComp); move.direction = 1; // 向右移动 move.targetX = 0; // 右边界' if(HeroInfo[uuid].type==HType.remote){ diff --git a/assets/script/game/hero/HeroMove.ts b/assets/script/game/hero/HeroMove.ts new file mode 100644 index 00000000..c18adba4 --- /dev/null +++ b/assets/script/game/hero/HeroMove.ts @@ -0,0 +1,264 @@ +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 { HType } from "../common/config/heroSet"; +import { Attrs } from "../common/config/HeroAttrs"; + +/** 英雄移动组件 */ +@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) { + if (!smc.mission.play || smc.mission.pause) return; + + const move = e.get(HeroMoveComp); + const model = e.get(HeroAttrsComp); + const view = e.get(HeroViewComp); + + // 只处理英雄 + if (model.fac !== FacSet.HERO) 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 hasEnemies = this.checkEnemiesExist(e); + const isWarrior = model.type === HType.warrior; + + // 战士职业:有敌人就向敌人前进 + if (isWarrior && hasEnemies) { + const nearestEnemy = this.findNearestEnemy(e); + if (nearestEnemy) { + const enemyX = nearestEnemy.node.position.x; + const currentX = view.node.position.x; + + // 根据敌人位置调整移动方向和朝向 + if (enemyX > currentX) { + move.direction = 1; // 向右移动 + view.node.setScale(1, 1, 1); // 面向右侧 + view.node.getChildByName("top").setScale(1, 1, 1); // 面向右侧 + } else { + move.direction = -1; // 向左移动 + view.node.setScale(-1, 1, 1); // 面向左侧 + view.node.getChildByName("top").setScale(-1, 1, 1); // 面向左侧 + } + + // 继续向敌人方向移动 + const delta = (model.Attrs[Attrs.SPEED]/3) * this.dt * move.direction; + const newX = view.node.position.x + delta; + + // 对于战士,允许更自由的移动范围 + if (newX >= -420 && newX <= 420) { // 使用地图边界 + view.status_change("move"); + view.node.setPosition(newX, view.node.position.y, 0); + } else { + view.status_change("idle"); + } + } + return; + } + + // 其他职业或战士无敌人时:回到预定点 + const currentX = view.node.position.x; + let finalTargetX = move.targetX; + + // 检查预定点是否已被占用 + if (this.isPositionOccupied(finalTargetX, e)) { + finalTargetX = move.targetX - 50; // 往前50的位置 + } + + // 如果不在目标位置,移动到目标位置 + if (Math.abs(currentX - finalTargetX) > 1) { + // 确定移动方向 + const direction = currentX > finalTargetX ? -1 : 1; + const delta = (model.Attrs[Attrs.SPEED]/3) * this.dt * direction; + const newX = view.node.position.x + delta; + + // 设置朝向 + if (direction === 1) { + view.node.setScale(1, 1, 1); // 面向右侧 + view.node.getChildByName("top").setScale(1, 1, 1); // 面向右侧 + } else { + view.node.setScale(-1, 1, 1); // 面向左侧 + view.node.getChildByName("top").setScale(-1, 1, 1); // 面向左侧 + } + + // 确保不会超过目标位置 + if (direction === 1 && newX > finalTargetX) { + view.node.setPosition(finalTargetX, view.node.position.y, 0); + } else if (direction === -1 && newX < finalTargetX) { + view.node.setPosition(finalTargetX, view.node.position.y, 0); + } else { + view.node.setPosition(newX, view.node.position.y, 0); + } + view.status_change("move"); + } else { + view.status_change("idle"); + // 到达目标位置后,面向右侧(敌人方向) + move.direction = 1; + view.node.setScale(1, 1, 1); // 面向右侧 + view.node.getChildByName("top").setScale(1, 1, 1); // 面向右侧 + } + } else { + view.status_change("idle"); + // 因为敌人在面前而暂时停止,不设置moving为false,保持检查状态 + } + } + + /** 检查是否存在敌人 */ + private checkEnemiesExist(entity: ecs.Entity): boolean { + const team = entity.get(HeroAttrsComp).fac; + let hasEnemies = false; + ecs.query(ecs.allOf(HeroAttrsComp)).some(e => { + const model = e.get(HeroAttrsComp); + if (model.fac !== team && !model.is_dead) { + hasEnemies = true; + return true; + } + }); + return hasEnemies; + } + + /** 找到最近的敌人 */ + private findNearestEnemy(entity: ecs.Entity): HeroViewComp | null { + const currentPos = entity.get(HeroViewComp).node.position; + const team = entity.get(HeroAttrsComp).fac; + let nearestEnemyView: HeroViewComp | null = null; + let minDistance = Infinity; + + ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => { + const model = e.get(HeroAttrsComp); + const view = e.get(HeroViewComp); + if (model.fac !== team && !model.is_dead) { + const distance = Math.abs(currentPos.x - view.node.position.x); + if (distance < minDistance) { + minDistance = distance; + nearestEnemyView = view; + } + } + }); + + return nearestEnemyView; + } + + /** 检测攻击范围内敌人 */ + private checkEnemiesInRange(entity: ecs.Entity, range: number): boolean { + const currentPos = entity.get(HeroViewComp).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); + 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 currentPos = entity.get(HeroViewComp).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); + 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 posA = a.get(HeroViewComp).node.position.x; + const posB = b.get(HeroViewComp).node.position.x; + return posA - posB; // x坐标从小到大排序 + }); + + // 设置渲染顺序:x坐标越大的显示在上层(index越大,层级越高) + sortedUnits.forEach((unit, index) => { + const model = unit.get(HeroViewComp); + model.node.setSiblingIndex(index); // 直接使用index,x坐标大的index大,层级高 + }); + } + + /** 检查指定位置是否已被占用 */ + private isPositionOccupied(targetX: number, currentEntity: ecs.Entity): boolean { + const currentModel = currentEntity.get(HeroAttrsComp); + const occupationRange = 30; // 定义占用范围为30像素 + + return ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => { + if (e === currentEntity) return false; // 排除自己 + + const model = e.get(HeroAttrsComp); + const view = e.get(HeroViewComp); + if (model.fac !== currentModel.fac) return false; // 只检查同阵营 + if (model.is_dead) return false; // 排除死亡单位 + + const distance = Math.abs(view.node.position.x - targetX); + return distance < occupationRange; // 如果距离小于占用范围,认为被占用 + }); + } +} \ No newline at end of file diff --git a/assets/script/game/common/ecs/position/BattleMoveComp.ts.meta b/assets/script/game/hero/HeroMove.ts.meta similarity index 70% rename from assets/script/game/common/ecs/position/BattleMoveComp.ts.meta rename to assets/script/game/hero/HeroMove.ts.meta index 87cba881..5927dd1c 100644 --- a/assets/script/game/common/ecs/position/BattleMoveComp.ts.meta +++ b/assets/script/game/hero/HeroMove.ts.meta @@ -2,7 +2,7 @@ "ver": "4.0.24", "importer": "typescript", "imported": true, - "uuid": "196aaacb-556c-4bb2-925c-9a70dc3e56fc", + "uuid": "b8ffb934-e91e-466c-a857-5f88cc83b542", "files": [], "subMetas": {}, "userData": {} diff --git a/assets/script/game/hero/Mon.ts b/assets/script/game/hero/Mon.ts index 62173555..5895c7d1 100644 --- a/assets/script/game/hero/Mon.ts +++ b/assets/script/game/hero/Mon.ts @@ -5,24 +5,23 @@ import { smc } from "../common/SingletonModuleComp"; import { BoxSet, FacSet } from "../common/config/BoxSet"; import { HeroInfo } from "../common/config/heroSet"; import { HeroAttrsComp } from "./HeroAttrsComp"; -import { BattleMoveComp } from "../common/ecs/position/BattleMoveComp"; -import { SkillConComp } from "./SkillConComp"; import { BuffConf, SkillSet } from "../common/config/SkillSet"; import { getNeAttrs, getAttrs ,Attrs} from "../common/config/HeroAttrs"; import { getMonAttr, MonType } from "../map/RogueConfig"; import { HeroViewComp } from "./HeroViewComp"; import { HeroSkillsComp } from "./HeroSkills"; +import { MonMoveComp } from "./MonMove"; /** 角色实体 */ @ecs.register(`Monster`) export class Monster extends ecs.Entity { HeroModel!: HeroAttrsComp; HeroSkills!: HeroSkillsComp; HeroView!: HeroViewComp; - BattleMove!: BattleMoveComp; + MonMove!: MonMoveComp; protected init() { this.addComponents( - BattleMoveComp, + MonMoveComp, HeroAttrsComp, HeroSkillsComp, ); @@ -89,7 +88,7 @@ export class Monster extends ecs.Entity { oops.message.dispatchEvent("monster_load",this) // 初始化移动参数 - const move = this.get(BattleMoveComp); + const move = this.get(MonMoveComp); move.direction = -1; // 向左移动 move.targetX = -800; // 左边界 smc.vmdata.mission_data.mon_num++ diff --git a/assets/script/game/hero/MonMove.ts b/assets/script/game/hero/MonMove.ts new file mode 100644 index 00000000..a4a77dfa --- /dev/null +++ b/assets/script/game/hero/MonMove.ts @@ -0,0 +1,153 @@ +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 currentPos = entity.get(HeroViewComp).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); + 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 currentPos = entity.get(HeroViewComp).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); + 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 posA = a.get(HeroViewComp).node.position.x; + const posB = b.get(HeroViewComp).node.position.x; + return posA - posB; // x坐标从小到大排序 + }); + + // 设置渲染顺序:x坐标越大的显示在上层(index越大,层级越高) + sortedUnits.forEach((unit, index) => { + const model = unit.get(HeroViewComp); + model.node.setSiblingIndex(index); // 直接使用index,x坐标大的index大,层级高 + }); + } +} \ No newline at end of file diff --git a/assets/script/game/common/ecs/position/EcsPositionSystem.ts.meta b/assets/script/game/hero/MonMove.ts.meta similarity index 70% rename from assets/script/game/common/ecs/position/EcsPositionSystem.ts.meta rename to assets/script/game/hero/MonMove.ts.meta index 2900eb81..48ea3d7a 100644 --- a/assets/script/game/common/ecs/position/EcsPositionSystem.ts.meta +++ b/assets/script/game/hero/MonMove.ts.meta @@ -2,7 +2,7 @@ "ver": "4.0.24", "importer": "typescript", "imported": true, - "uuid": "b44c446b-ce5f-4079-ac42-269837dbf580", + "uuid": "8993c5a5-5b0a-4814-b53b-8cc441e9a359", "files": [], "subMetas": {}, "userData": {}