import { instantiate, Node, Prefab, Vec3 ,v3,resources,SpriteFrame,Sprite,SpriteAtlas, BoxCollider2D, NodePool} from "cc"; import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { smc } from "../common/SingletonModuleComp"; import { BoxSet, FacSet, FightSet, IndexSet } from "../common/config/GameSet"; import { HeroInfo } from "../common/config/heroSet"; import { HeroAttrsComp } from "./HeroAttrsComp"; import { BuffConf, SkillSet } from "../common/config/SkillSet"; import { getMonAttr, MonType } from "../map/RogueConfig"; import { HeroViewComp } from "./HeroViewComp"; import { MonMoveComp } from "./MonMove"; import { mLogger } from "../common/Logger"; /** 角色实体 */ @ecs.register(`Monster`) export class Monster extends ecs.Entity { HeroModel!: HeroAttrsComp; HeroView!: HeroViewComp; MonMove!: MonMoveComp; private debugMode: boolean = false; // 是否启用调试模式 // 多键对象池:Map static pools: Map = new Map(); static getFromPool(path: string): Node | null { if (this.pools.has(path)) { const pool = this.pools.get(path)!; if (pool.size() > 0) { return pool.get(); } } return null; } static putToPool(path: string, node: Node) { if (!this.pools.has(path)) { this.pools.set(path, new NodePool()); } this.pools.get(path)!.put(node); } protected init() { this.addComponents( MonMoveComp, HeroAttrsComp, ); } destroy(): void { // 回收节点到对象池 const model = this.get(HeroAttrsComp); const view = this.get(HeroViewComp); if (model && view && view.node && view.node.isValid) { const path = "game/heros/" + HeroInfo[model.hero_uuid].path; Monster.putToPool(path, view.node); } this.remove(HeroViewComp); this.remove(HeroAttrsComp); super.destroy(); } /** 加载角色 */ load(pos: Vec3 = Vec3.ZERO,scale:number = 1,uuid:number=1001,lv:number=1,monType:MonType=MonType.NORMAL, buffs: BuffConf[] = [],is_call=false, lane: number = 0, spawnOrder: number = 0, gameTime: number = 0) { scale=-1 let size=1 var scene = smc.map.MapView.scene; var path = "game/heros/"+HeroInfo[uuid].path; // 尝试从池中获取 let node = Monster.getFromPool(path); if (!node) { var prefab: Prefab = oops.res.get(path, Prefab)!; node = instantiate(prefab); } let LINE1=scene.entityLayer!.node!.getChildByName("LINE1")!; let LINE2=scene.entityLayer!.node!.getChildByName("LINE2")!; let LINE3=scene.entityLayer!.node!.getChildByName("LINE3")!; let LINE4=scene.entityLayer!.node!.getChildByName("LINE4")!; // 🔥 设置初始 SiblingIndex - 防止溢出 const baseLane = lane === 0 ? LINE1 : lane === 1 ? LINE2 : lane === 2 ? LINE3 : LINE4; node.parent = baseLane var view = node.getComponent(HeroViewComp)!; const collider = node.getComponent(BoxCollider2D); if (collider) { // 先禁用,下一帧启用,确保物理系统能正确注册新激活的节点 collider.enabled = false; view.scheduleOnce(() => { if (node && node.isValid) { collider.enabled = true; collider.group = BoxSet.MONSTER; // 确保碰撞组正确 collider.apply(); // 强制应用更改(如果需要) } }, 0); // 0延迟等于下一帧执行 } node.setScale(size*node.scale.x,size*node.scale.y); node.setPosition(pos) const model = this.get(HeroAttrsComp); let hero = HeroInfo[uuid]; // 共用英雄数据 // 设置 View 层属性(表现相关) view.scale = scale; view.box_group = BoxSet.MONSTER; // 设置 Model 层属性(数据相关) model.hero_uuid = uuid; model.hero_name = hero.name; model.lv = lv; model.type = hero.type; model.fac = FacSet.MON; model.is_boss = monType == MonType.BOSS; if(model.is_boss) node.parent = scene.entityLayer!.node!.getChildByName("HERO")!; if(!model.is_boss){ model.is_kalami = true; } // 根据等级和类型获取怪物属性(使用新的动态成长系统) const {hp,ap, speed} = getMonAttr(lv, uuid, monType, gameTime); // 初始化属性数组 model.hp = model.hp_max = hp; model.ap = ap; model.speed = speed; // 使用成长后的速度 model.a_cd_max=hero.as model.s_cd_max=hero.ss model.back_chance=FightSet.BACK_CHANCE // ✅ 初始化技能数据(迁移到 HeroSkillsComp) if(hero.skills[0]) model.atk_id=hero.skills[0] if(hero.skills[1]) model.skill_id=hero.skills[1] model.updateSkillDistanceCache(model.skill_id || model.atk_id); this.add(view); // 重置视图状态(对象池复用时必须) view.init(); oops.message.dispatchEvent("monster_load",this) // 初始化移动参数,包括线路和生成顺序 const move = this.get(MonMoveComp); move.reset(); move.direction = -1; // 向左移动 move.targetX = -800; // 左边界 move.lane = lane; // 设置线路标识 move.spawnOrder = spawnOrder; // 设置生成顺序 smc.vmdata.mission_data.mon_num++ } reset() { // 注: 自定义释放逻辑,视图层实现 ecs.IComp 接口的 ecs 组件需要手动释放 super.destroy(); } } @ecs.register('MonLifecycleSystem') export class MonLifecycleSystem extends ecs.ComblockSystem implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem { debugMode: boolean = false; // 是否启用调试模式 filter() { return ecs.allOf(MonMoveComp); } entityEnter(e: ecs.Entity): void { // 怪物实体创建时的特殊处理 const heroAttrs = e.get(HeroAttrsComp); if (heroAttrs) { mLogger.log(this.debugMode, 'MonLifecycleSystem', `怪物进入世界: ${heroAttrs.hero_name}`); } else { mLogger.log(this.debugMode, 'MonLifecycleSystem', `怪物进入世界: 实体ID ${e.eid}`); } } entityRemove(e: ecs.Entity): void { // 怪物实体销毁时的清理工作 const heroAttrs = e.get(HeroAttrsComp); if (heroAttrs) { mLogger.log(this.debugMode, 'MonLifecycleSystem', `怪物离开世界: ${heroAttrs.hero_name}`); } else { mLogger.log(this.debugMode, 'MonLifecycleSystem', `怪物离开世界: 实体ID ${e.eid}`); } } }