import { _decorator, v3, Vec3 } from "cc"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; import { Monster } from "../hero/Mon"; import { MonStart } from "../common/config/heroSet"; import { smc } from "../common/SingletonModuleComp"; import { GameEvent } from "../common/config/GameEvent"; // 导入肉鸽配置 import { getStageMonConfigs, MonType, generateMonstersFromBudget, getRogueConfig } from "./RogueConfig"; import { BuffConf } from "../common/config/SkillSet"; import { IndexSet, FacSet, BoxSet } from "../common/config/GameSet"; import { HeroAttrsComp } from "../hero/HeroAttrsComp"; import { Attrs } from "../common/config/HeroAttrs"; const { ccclass, property } = _decorator; /** 视图层对象 */ @ccclass('MissionMonCompComp') @ecs.register('MissionMonComp', false) export class MissionMonCompComp extends CCComp { // 添加刷怪队列 - 使用新的RogueConfig格式 private MonQueue: Array<{ uuid: number, position: number, type: MonType, level: number, buffs: BuffConf[] }> = []; private isSpawning: boolean = false;// 是否正在生成怪物 private spawnInterval: number = 0.6; // 每个怪物生成间隔时间(减半速度) private spawnTimer: number = 0; // 生成计时器 private spawnCount: number = 0; // 召唤计数器 // private pauseInterval: number = 5.0; // 暂停间隔时间(5秒) // private isPausing: boolean = false; // 是否正在暂停 private eventProcessed: boolean = false; // 事件是否已处理 /** 全局生成顺序计数器,用于层级管理 */ private globalSpawnOrder: number = 0; /** 游戏进行时间(秒) */ private gameTime: number = 0; /** 刷怪逻辑计时器(每秒执行一次) */ private spawnLogicTimer: number = 0; onLoad(){ this.on(GameEvent.FightReady,this.fight_ready,this) this.on(GameEvent.NewWave,this.fight_ready,this) // 监听特殊刷怪事件 (精英/Boss) this.on("SpawnSpecialMonster", this.onSpawnSpecialMonster, this); } /** * 处理特殊刷怪事件 * @param event 事件名 * @param args 参数 { uuid, type, level, position?, buffs? } */ private onSpawnSpecialMonster(event: string, args: any) { if (!args) return; console.log(`[MissionMonComp] 收到特殊刷怪指令:`, args); // 插入队列头部,优先生成 this.MonQueue.unshift({ uuid: args.uuid, position: args.position !== undefined ? args.position : 2, // 默认中间 type: args.type, level: args.level, buffs: args.buffs || [] }); // 让刷怪计时器立即满足条件,以便尽快生成 // 注意:不直接调用 spawnNextMonster 是为了保持 update 循环的一致性 const config = getRogueConfig(); this.spawnTimer = config.spawnInterval + 0.1; } /** 视图层逻辑代码分离演示 */ start() { // var entity = this.ent as ecs.Entity; // ecs.Entity 可转为当前模块的具体实体对象 // this.on(ModuleEvent.Cmd, this.onHandler, this); } fight_ready(){ // console.log("[MissionMonComp]:fight_ready") smc.vmdata.mission_data.mon_num=0 // 重置生成顺序计数器 this.globalSpawnOrder = 0 this.gameTime = 0 this.spawnLogicTimer = 0 this.MonQueue = [] this.do_mon_wave() } protected update(dt: number): void { if(!smc.mission.play) return if(smc.mission.pause) return // 如果英雄死亡(停止怪物行动标志为true),则停止刷怪逻辑 if(smc.mission.stop_mon_action) return; // 累加游戏时间 this.gameTime += dt; const config = getRogueConfig(); // ========================================== // 新增:每秒执行一次刷怪逻辑 (Threat Budget) // ========================================== this.spawnLogicTimer += dt; if (this.spawnLogicTimer >= config.spawnLogicInterval) { this.spawnLogicTimer = 0; // 检查最大怪物数量限制 if (smc.vmdata.mission_data.mon_num < config.maxMonsterCount) { // 获取英雄血量比例 const hpRatio = this.getHeroHpRatio(); // 生成怪物 const newMonsters = generateMonstersFromBudget(this.gameTime, hpRatio); // 添加到队列 newMonsters.forEach(mon => { this.addToStageSpawnQueue( mon.uuid, mon.position !== undefined ? mon.position : 0, mon.type, mon.level, mon.buffs || [] ); }); } } // 处理随机事件 // 处理刷怪队列 if (this.MonQueue.length > 0 && !this.isSpawning) { this.spawnTimer += dt; // 正常召唤间隔 if (this.spawnTimer >= config.spawnInterval) { this.spawnNextMonster(); this.spawnTimer = 0; } } } do_mon_wave(){ // 重置召唤相关状态 this.spawnCount = 0; // this.isPausing = false; this.spawnTimer = 0; this.eventProcessed = false; // const cStage = smc.data.mission; // // 使用新的肉鸽关卡配置 // let level=smc.vmdata.mission_data.level // const monsConf = getStageMonConfigs(cStage); // // console.log(`[MissionMonComp]:第${cStage}关 - ${stageType}类型,怪物数量: ${monsConf.length}`); // const monsConfFiltered = monsConf.filter((mon: any, index) => index === 0); // this.generateMonsters(monsConfFiltered); console.log("[MissionMonComp] Starting Threat Budget Wave System"); } /** * 获取英雄血量比例 */ private getHeroHpRatio(): number { // 查询带有 HeroAttrsComp 的实体 // 注意:这里假设只有一个英雄,且性能允许每秒查询一次 const entities = ecs.query(ecs.allOf(HeroAttrsComp)); for (const e of entities) { const attrs = e.get(HeroAttrsComp); if (attrs && attrs.fac === FacSet.HERO) { const maxHp = attrs.Attrs[Attrs.HP_MAX] || 1; return attrs.hp / maxHp; } } return 1.0; // 默认满血 } // 根据新的关卡配置生成怪物 private generateMonsters(monsConf: any[]) { const cStage = smc.data.mission; // 设置怪物总数 // console.log("[MissionMonComp] generateMonsters",monsConf) if (!monsConf || monsConf.length === 0) { console.warn(`[MissionMonComp]:关卡${cStage}配置中没有怪物信息`); return; } // 为每个怪物配置生成怪物 monsConf.forEach((mon: any, index: number) => { const { uuid, type, level, buffs, position } = mon; // 使用配置中的位置,如果没有则使用索引 const spawnPosition = position !== undefined ? position : (index % 5); this.addToStageSpawnQueue( uuid, spawnPosition, type, level, buffs ); }); // console.log(`[MissionMonComp]:关卡${cStage}将生成 ${monsConf.length} 只怪物`); } // 添加到关卡刷怪队列 - 使用新的配置格式 private addToStageSpawnQueue( uuid: number, position: number, type: MonType = MonType.NORMAL, level: number = 1, buffs: BuffConf[] = [] ) { this.MonQueue.push({ uuid: uuid, position: position, type: type, level: level, buffs: buffs }); } // 从队列中生成下一个怪物 - 使用新的配置格式 private spawnNextMonster() { if (this.MonQueue.length === 0) return; const monsterData = this.MonQueue.shift(); if (monsterData) { this.addMonster( monsterData.uuid, monsterData.position, monsterData.type, monsterData.level, monsterData.buffs, this.gameTime ); // 增加召唤计数 this.spawnCount++; // console.log(`[MissionMonComp]: 召唤第${this.spawnCount}只${monsterData.type}怪物,剩余队列: ${this.MonQueue.length}`); } } private addMonster( uuid: number = 1001, i: number = 0, monType: number = 0, lv: number = 1, buffs: BuffConf[] = [], gameTime: number = 0 ) { let mon = ecs.getEntity(Monster); let scale = -1; // 使用 MonStart 计算怪物出生位置: // x 从 START_X 开始,按 START_I 的间隔递增; // y 在线路之间交替:0->SLINE_1, 1->SLINE_2, 2->SLINE_3, 3->SLINE_4 const x = MonStart.START_X + Math.floor(i / 4) * MonStart.START_I; let y = BoxSet.GAME_LINE; let lane = 0; // switch (i % 4) { // case 0: // y = MonStart.SLINE_1; // lane = 0; // break; // case 1: // y = MonStart.SLINE_2; // lane = 1; // break; // case 2: // y = MonStart.SLINE_3; // lane = 2; // break; // case 3: // y = MonStart.SLINE_4; // lane = 3; // break; // } let pos: Vec3 = v3(x, y, 0); // 递增全局生成顺序 - 🔥 添加溢出保护 this.globalSpawnOrder = (this.globalSpawnOrder + 1) % 999; // 防止无限增长,在999处循环重置 // 生成怪物,传递线路和生成顺序 mon.load(pos, scale, uuid, lv, monType, buffs, false, lane, this.globalSpawnOrder, gameTime); } /** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */ reset() { // this.node.destroy(); } }