diff --git a/assets/script/game/map/MissionMonComp.ts b/assets/script/game/map/MissionMonComp.ts index 49b52b6a..dd2a98ac 100644 --- a/assets/script/game/map/MissionMonComp.ts +++ b/assets/script/game/map/MissionMonComp.ts @@ -6,7 +6,7 @@ import { MonStart } from "../common/config/heroSet"; import { smc } from "../common/SingletonModuleComp"; import { GameEvent } from "../common/config/GameEvent"; // 导入肉鸽配置 -import { getStageMonConfigs, MonType, generateMonstersFromBudget } from "./RogueConfig"; +import { getStageMonConfigs, MonType, generateMonstersFromBudget, getRogueConfig } from "./RogueConfig"; import { BuffConf } from "../common/config/SkillSet"; import { IndexSet, FacSet } from "../common/config/GameSet"; import { HeroAttrsComp } from "../hero/HeroAttrsComp"; @@ -64,30 +64,34 @@ export class MissionMonCompComp extends CCComp { // 累加游戏时间 this.gameTime += dt; + const config = getRogueConfig(); // ========================================== // 新增:每秒执行一次刷怪逻辑 (Threat Budget) // ========================================== this.spawnLogicTimer += dt; - if (this.spawnLogicTimer >= 1.0) { + if (this.spawnLogicTimer >= config.spawnLogicInterval) { this.spawnLogicTimer = 0; - // 获取英雄血量比例 - 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 (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 || [] + ); + }); + } } // 处理随机事件 @@ -98,7 +102,7 @@ export class MissionMonCompComp extends CCComp { this.spawnTimer += dt; // 正常召唤间隔 - if (this.spawnTimer >= this.spawnInterval) { + if (this.spawnTimer >= config.spawnInterval) { this.spawnNextMonster(); this.spawnTimer = 0; } diff --git a/assets/script/game/map/RogueConfig.ts b/assets/script/game/map/RogueConfig.ts index f971a9d9..3f5176bc 100644 --- a/assets/script/game/map/RogueConfig.ts +++ b/assets/script/game/map/RogueConfig.ts @@ -21,7 +21,7 @@ import { HeroInfo } from "../common/config/heroSet"; -// 精英怪物配置表 + @@ -241,28 +241,87 @@ function getSpawnWeights(timeInSeconds: number): SpawnWeight[] { } } + +/** + * 全局刷怪配置接口 + */ +export interface IRogueGlobalConfig { + /** 场上最大怪物数量限制 */ + maxMonsterCount: number; + /** 刷怪逻辑执行间隔(秒) - 决定多久计算一次生成 */ + spawnLogicInterval: number; + /** 单个怪物生成间隔(秒) - 队列中怪物的实际生成频率 */ + spawnInterval: number; + /** 基础威胁预算 - 每秒产生的基础点数 */ + baseBudget: number; + /** 时间难度因子 - 每分钟增加的预算比例 (0.2 = 20%) */ + timeDifficultyFactor: number; + /** 绝地求生阈值 - 英雄血量低于此比例时触发减缓刷怪 */ + survivalHpThreshold: number; + /** 绝地求生预算乘数 - 触发阈值时的预算折扣 */ + survivalBudgetMultiplier: number; + /** 单次逻辑最大生成怪物数限制 - 防止瞬间生成过多 */ + maxSpawnPerLogic: number; +} + +/** + * 默认配置 + */ +export const DefaultRogueConfig: IRogueGlobalConfig = { + maxMonsterCount: 50, // 默认同屏50只 + spawnLogicInterval: 1.0, // 每秒计算一次 + spawnInterval: 0.6, // 队列出怪间隔0.6秒 + baseBudget: 1.5, // 基础预算 + timeDifficultyFactor: 0.2, // 每分钟增加20%预算 + survivalHpThreshold: 0.4, // 40%血量触发保护 + survivalBudgetMultiplier: 0.7, // 保护时预算打7折 + maxSpawnPerLogic: 10 // 单次最多生成10只 +}; + +// 当前配置实例 +let currentConfig: IRogueGlobalConfig = { ...DefaultRogueConfig }; + +/** + * 获取当前全局配置 + */ +export function getRogueConfig(): IRogueGlobalConfig { + return currentConfig; +} + +/** + * 更新全局配置 + * @param config 部分或全部配置 + */ +export function updateRogueConfig(config: Partial) { + currentConfig = { + ...currentConfig, + ...config + }; + console.log("[RogueConfig] Configuration updated:", currentConfig); +} + /** * 计算当前威胁点数预算 * @param timeInSeconds 游戏时间(秒) * @param heroHpRatio 英雄血量比例 (0-1) */ export function calculateBudget(timeInSeconds: number, heroHpRatio: number = 1.0): number { - // 基础预算:每秒产生的点数 - // 假设1分钟时为20点,公式: Budget = Base * (1 + 60/60 * 0.2) = Base * 1.2 = 20 => Base ≈ 16 - // 修改:降低基础预算,避免队列积压。每秒 1.5 点左右(减半)。 - const Base_Budget = 1.5; + const config = getRogueConfig(); + + // 基础预算 + const Base_Budget = config.baseBudget; // 时间因子:随时间增加难度 - const timeFactor = 1 + (timeInSeconds / 60) * 0.2; + const timeFactor = 1 + (timeInSeconds / 60) * config.timeDifficultyFactor; // 强度乘数 (DDA):根据英雄状态调整 let intensityMultiplier = 1.0; - if (heroHpRatio < 0.4) { - // 绝地求生:血量低于40%时,预算缩减30% - intensityMultiplier = 0.7; + if (heroHpRatio < config.survivalHpThreshold) { + // 绝地求生:血量低于阈值时预算缩减 + intensityMultiplier = config.survivalBudgetMultiplier; } - // 公式: Budget(t) = Base_Budget * (1 + t/60 * 0.2) * Intensity_Multiplier + // 公式: Budget(t) = Base_Budget * (1 + t/60 * Factor) * Intensity_Multiplier return Math.floor(Base_Budget * timeFactor * intensityMultiplier); } @@ -272,17 +331,15 @@ export function calculateBudget(timeInSeconds: number, heroHpRatio: number = 1.0 * @param heroHpRatio 英雄血量比例 */ export function generateMonstersFromBudget(timeInSeconds: number, heroHpRatio: number = 1.0): IMonsConfig[] { - // 15分钟后只生成Boss,且如果已经有Boss可能需要控制(这里简化为每次调用都尝试生成,由外部控制频率或唯一性) - // 但根据"清除所有杂兵,锁定刷出最终BOSS",这里只返回Boss配置 + const config = getRogueConfig(); + + // 15分钟后只生成Boss if (timeInSeconds >= 15 * 60) { - // 可以在这里做特殊处理,比如只返回一个Boss,或者返回空如果Boss已存在 - // 假设外部每秒调用,这里返回Boss,外部队列会堆积。 - // 建议:Boss波次由特殊逻辑控制,或者这里返回Boss但消耗巨大预算 return [{ uuid: 5701, type: MonType.BOSS, - level: Math.floor(timeInSeconds / 60), // 等级随时间 - position: 2 // 中间位置 + level: Math.floor(timeInSeconds / 60), + position: 2 }]; } @@ -300,29 +357,27 @@ export function generateMonstersFromBudget(timeInSeconds: number, heroHpRatio: n if (pool.length === 0) return []; let attempts = 0; - // 尝试消耗预算直到耗尽或无法购买最便宜的怪物 const minCost = Math.min(...weights.map(w => MonsterCost[w.uuid] || 1)); - while (currentBudget >= minCost && attempts < 50) { + // 限制单次生成最大数量 + while (currentBudget >= minCost && attempts < 50 && monsters.length < config.maxSpawnPerLogic) { attempts++; - // 随机选择怪物 const uuid = pool[Math.floor(Math.random() * pool.length)]; const cost = MonsterCost[uuid] || 1; if (currentBudget >= cost) { currentBudget -= cost; - // 确定怪物类型 let type = MonType.NORMAL; - if (uuid === 5701) type = MonType.BOSS; // 或者是精英,视情况而定 + if (uuid === 5701) type = MonType.BOSS; else if (MonsterCost[uuid] >= 10) type = MonType.ELITE; monsters.push({ uuid: uuid, type: type, - level: Math.floor(timeInSeconds / 60) + 1, // 简单等级计算,实际属性由getMonAttr处理 - position: Math.floor(Math.random() * 5) // 随机位置 0-4 + level: Math.floor(timeInSeconds / 60) + 1, + position: Math.floor(Math.random() * 5) }); } }