diff --git a/assets/script/game/hero/Mon.ts b/assets/script/game/hero/Mon.ts index 6fc00e2e..17f7882f 100644 --- a/assets/script/game/hero/Mon.ts +++ b/assets/script/game/hero/Mon.ts @@ -70,15 +70,15 @@ export class Monster extends ecs.Entity { if(!model.is_boss){ model.is_kalami = true; } - // 根据等级和类型获取怪物属性 - const {hp, mp, ap,def} = getMonAttr(lv, uuid, monType); - // 初始化属性数组 + // 根据等级和类型获取怪物属性(使用新的动态成长系统) + const {hp, mp, ap, def, speed} = getMonAttr(lv, uuid, monType); + // 初始化属性数组 model.Attrs = getAttrs(); model.hp = model.Attrs[Attrs.HP_MAX] = hp; model.mp = model.Attrs[Attrs.MP_MAX] = mp; model.Attrs[Attrs.DEF] = def; model.Attrs[Attrs.AP] = ap; - model.Attrs[Attrs.SPEED] = hero.speed; + model.Attrs[Attrs.SPEED] = speed; // 使用成长后的速度 model.Attrs[Attrs.DIS] = hero.dis; // ✅ 初始化技能数据(迁移到 HeroSkillsComp) diff --git a/assets/script/game/map/MissionMonComp.ts b/assets/script/game/map/MissionMonComp.ts index eb205bb7..4ff881e7 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 { MonType, EventType, getStageMonConfigs} from "./RogueConfig"; +import { getStageMonConfigs, MonType } from "./RogueConfig"; import { BuffConf } from "../common/config/SkillSet"; import { IndexSet } from "../common/config/GameSet"; const { ccclass, property } = _decorator; @@ -17,9 +17,9 @@ const { ccclass, property } = _decorator; export class MissionMonCompComp extends CCComp { // 添加刷怪队列 - 使用新的RogueConfig格式 private MonQueue: Array<{ - uuid: number, - position: number, - type: MonType + uuid: number, + position: number, + type: MonType, level: number, buffs: BuffConf[] }> = []; @@ -29,7 +29,6 @@ export class MissionMonCompComp extends CCComp { private spawnCount: number = 0; // 召唤计数器 private pauseInterval: number = 5.0; // 暂停间隔时间(5秒) private isPausing: boolean = false; // 是否正在暂停 - private currentEvent: EventType | null = null; // 当前关卡的随机事件 private eventProcessed: boolean = false; // 事件是否已处理 /** 全局生成顺序计数器,用于层级管理 */ private globalSpawnOrder: number = 0; @@ -58,10 +57,7 @@ export class MissionMonCompComp extends CCComp { if(!smc.mission.play||smc.mission.pause) return // 处理随机事件 - if (this.currentEvent && !this.eventProcessed) { - - this.eventProcessed = true; - } + // 处理刷怪队列 if (this.MonQueue.length > 0 && !this.isSpawning) { @@ -116,38 +112,38 @@ export class MissionMonCompComp extends CCComp { // 根据新的关卡配置生成怪物 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 } = mon; - - // 位置循环使用 (0-4) - const position = index % 5; - + const { uuid, type, level, buffs, position } = mon; + + // 使用配置中的位置,如果没有则使用索引 + const spawnPosition = position !== undefined ? position : (index % 5); + this.addToStageSpawnQueue( - uuid, - position, + uuid, + spawnPosition, type, - level, // 默认等级1 - buffs // 强度倍率 + level, + buffs ); }); - + // console.log(`[MissionMonComp]:关卡${cStage}将生成 ${monsConf.length} 只怪物`); } // 添加到关卡刷怪队列 - 使用新的配置格式 private addToStageSpawnQueue( - uuid: number, - position: number, - type: MonType, + uuid: number, + position: number, + type: MonType = MonType.NORMAL, level: number = 1, buffs: BuffConf[] = [] ) { @@ -182,7 +178,7 @@ export class MissionMonCompComp extends CCComp { private addMonster( uuid: number = 1001, i: number = 0, - monType: MonType = MonType.NORMAL, + monType: number = 0, lv: number = 1, buffs: BuffConf[] = [] diff --git a/assets/script/game/map/RogueConfig.ts b/assets/script/game/map/RogueConfig.ts index 9a04bdc9..b0ae5f93 100644 --- a/assets/script/game/map/RogueConfig.ts +++ b/assets/script/game/map/RogueConfig.ts @@ -1,19 +1,26 @@ /** * 肉鸽模式配置脚本 - 增强版 - * + * * 功能说明: * - 提供基础的刷怪配置:刷什么怪,刷多少怪 * - 支持程序化关卡生成逻辑,每一关的怪物组合、数量和强度应随关卡进度递增而变化 * - 支持随机事件系统 - * + * + * + * 3. 全局动态 Scaling 算法既然是 15 分钟单局,属性不应一成不变。 + * 建议引入 Wave_Factor (波次因子): + * 公式建议: Current_Stat = Base_Stat * (1 + (time / 60) * 0.15) ^ Growth_Type + * •HP 成长: 设为指数级 (Growth_Type = 1.2)。后期怪物血量会呈几何倍数增加,适配『神装英雄』。 + * •AP 成长: 设为线性 (Growth_Type = 1.0)。保证怪物能击穿后期护盾,但不会一击必杀。 + * •Speed 成长: 设为对数级 (Growth_Type = 0.5)。防止后期怪物速度过快导致画面瞬移。Donny DBM/Getty Images + * + * * @author 游戏开发团队 * @version 2.0 增强版 * @date 2025-10-19 */ -import { getMonList, HeroInfo } from "../common/config/heroSet"; -import { BuffConf } from "../common/config/SkillSet"; - +import { HeroInfo } from "../common/config/heroSet"; // 精英怪物配置表 export const EliteMons = [ 5201, 5202, 5203, 5213 ]; @@ -29,61 +36,111 @@ export const Mons={ /** * 怪物类型枚举 */ -export enum MonType { NORMAL = 0, ELITE = 1, BOSS = 2 } -export const EliteStage =[5,10,15,20,25] -export const BossStage=[30,40,50,60,70,80,90,100] - -export enum EventType { - TREASURE = 1, // 额外奖励 - TRAP =2, // 陷阱伤害 - BUFF = 3, // 临时增益效果 - DEBUFF = 4 // 临时减益效果 +export enum MonType { + NORMAL = 0, // 普通怪物 + ELITE = 1, // 精英怪物 + BOSS = 2 // Boss怪物 } /** - * 关卡生怪物相关配置 + * 怪物配置接口 */ -export const StageRule = { - MonsNum: 5, // 关卡中默认怪物数量 - LimitMonNum: 10, // 30关以后是极限模式,怪物数量 - /** 额外怪物出现概率(在固定5个怪物基础上,有概率多刷1个) */ - extraMonsterRate: 0.3, // 30%概率出现第6个怪物 - /** 事件怪物出现概率(5个怪物中有1个替换为事件怪) */ - eventMonsterRate: 0.25, // 25%概率出现事件怪物 - /** 特殊属性怪物出现概率(5个怪物中有怪物携带特殊属性) */ - specialAttributeRate: 0.4, // 40%概率出现特殊属性怪物 - /** 特殊属性怪物数量范围 */ - specialAttributeCount: { min: 1, max: 2 } // 出现时,1-2个怪物会有特殊属性 -}; - -interface IMonsConfig { - /** 怪物波次 */ - uuid: number; // 怪物ID - /** 怪物数量 */ - buff: BuffConf[]; //附加属性 - /** 怪物等级 */ - level: number; // 怪物等级 - /** 是否为精英怪物 */ - monType:MonType; +export interface IMonsConfig { + uuid: number; // 怪物ID + type: MonType; // 怪物类型 + level: number; // 等级 + position?: number; // 位置(可选) + buffs?: any[]; // buff列表(可选) } -export const MonAttrSet={ - [MonType.NORMAL]:{ HP_MAX:1.1, AP:1.05, MP:1.1, DEF:1.05,}, - [MonType.ELITE]: { HP_MAX:2, AP:1.1, MP:1.1, DEF:1.1,}, - [MonType.BOSS]: { HP_MAX:5, AP:2, MP:5, DEF:2,}, +/** + * 怪物属性接口 + */ +export interface MonAttrs { + hp: number; + mp: number; + ap: number; + def: number; + speed: number; } -export const MonBuffSet={ - +/** + * 成长类型枚举 + */ +enum GrowthType { + EXPONENTIAL = 1.2, // 指数级 - HP + LINEAR = 1.0, // 线性 - AP + LOGARITHMIC = 0.5 // 对数级 - Speed } -export const getMonAttr=(lv:number,uuid:number,MonType:MonType)=>{ - let mon=HeroInfo[uuid] - let hp=mon.hp*lv*MonAttrSet[MonType].HP_MAX - let mp=mon.mp*lv*MonAttrSet[MonType].MP - let ap=mon.ap*lv*MonAttrSet[MonType].AP - let def=mon.def*lv*MonAttrSet[MonType].DEF - return {hp:hp,mp:mp,ap:ap,def:def} +/** + * 计算波次因子 + * @param stage 当前波次 + * @param timeInSeconds 游戏进行时间(秒) + * @returns 波次因子 (0-1之间,15分钟时达到最大) + */ +function calculateWaveFactor(stage: number, timeInSeconds: number = 0): number { + const MAX_GAME_TIME = 15 * 60; // 15分钟 = 900秒 + const effectiveTime = timeInSeconds || (stage * 30); // 如果没有时间数据,用波次估算(每波30秒) + const factor = Math.min(effectiveTime / MAX_GAME_TIME, 1.0); + return factor; +} + +/** + * 应用成长公式到基础属性 + * @param baseStat 基础属性值 + * @param waveFactor 波次因子 (0-1) + * @param growthType 成长类型 + * @returns 成长后的属性值 + */ +function applyGrowthFormula(baseStat: number, waveFactor: number, growthType: GrowthType): number { + // 公式: Current_Stat = Base_Stat * (1 + waveFactor * 0.15) ^ Growth_Type + const growthMultiplier = Math.pow(1 + waveFactor * 0.15, growthType); + return Math.floor(baseStat * growthMultiplier); +} + +/** + * 获取怪物动态成长属性 + * @param stage 当前波次 + * @param uuid 怪物ID + * @param monType 怪物类型 + * @param timeInSeconds 游戏进行时间(秒) + * @returns 怪物属性 + */ +export function getMonAttr(stage: number, uuid: number, monType: MonType = MonType.NORMAL, timeInSeconds: number = 0): MonAttrs { + const baseMonster = HeroInfo[uuid]; + if (!baseMonster) { + console.warn(`[RogueConfig] 未找到怪物ID: ${uuid}`); + return { hp: 100, mp: 100, ap: 10, def: 0, speed: 100 }; + } + + // 计算波次因子 + const waveFactor = calculateWaveFactor(stage, timeInSeconds); + + // 根据怪物类型应用额外的倍率 + let typeMultiplier = 1.0; + if (monType === MonType.ELITE) { + typeMultiplier = 2.0; // 精英怪2倍属性 + } else if (monType === MonType.BOSS) { + typeMultiplier = 5.0; // Boss 5倍属性 + } + + // 应用不同的成长类型 + const hp = applyGrowthFormula(baseMonster.hp, waveFactor, GrowthType.EXPONENTIAL) * typeMultiplier; + const ap = applyGrowthFormula(baseMonster.ap, waveFactor, GrowthType.LINEAR) * typeMultiplier; + const speed = applyGrowthFormula(baseMonster.speed, waveFactor, GrowthType.LOGARITHMIC); + + // MP和DEF使用线性成长 + const mp = applyGrowthFormula(baseMonster.mp, waveFactor, GrowthType.LINEAR); + const def = applyGrowthFormula(baseMonster.def, waveFactor, GrowthType.LINEAR) * typeMultiplier; + + return { + hp: Math.floor(hp), + mp: Math.floor(mp), + ap: Math.floor(ap), + def: Math.floor(def), + speed: Math.floor(speed) + }; } /** @@ -93,84 +150,40 @@ export const getMonAttr=(lv:number,uuid:number,MonType:MonType)=>{ */ export function getStageMonConfigs(stage: number): IMonsConfig[] { const monsterConfigs: IMonsConfig[] = []; - - // 确定基础怪物数量 - let baseMonsterCount = StageRule.MonsNum; - - // 判断是否为Boss波次 - const isBossStage = BossStage.includes(stage); - - // 判断是否为精英波次 - const isEliteStage = EliteStage.includes(stage); - - // 如果是Boss波次,增加一个Boss怪物 - if (isBossStage) { - // 从Boss怪物列表中随机选择一个 - const bossUUID = BossMons[Math.floor(Math.random() * BossMons.length)] || 5201; + + // 基础怪物列表(从heroset.ts中获取) + const normalMons = [5201, 5301, 5401, 5501, 5601, 5602, 5603, 5604]; + const eliteMons = [5701]; + + // 根据波次生成怪物配置 + // 波次越高,怪物数量越多,精英怪物出现概率越高 + const baseCount = 5 + Math.floor(stage / 2); // 基础数量每2波增加1 + const eliteChance = Math.min(stage * 0.05, 0.3); // 精英怪概率最高30% + const bossWave = stage % 10 === 0; // 每10波出Boss + + if (bossWave && stage > 0) { + // Boss波 monsterConfigs.push({ - uuid: bossUUID, - buff: [], - level: stage, // Boss等级等于波次 - monType: MonType.BOSS + uuid: 5701, + type: MonType.BOSS, + level: stage }); - - // Boss波次减少普通怪物数量 - baseMonsterCount = Math.max(1, baseMonsterCount - 2); - } - - // 如果是精英波次,增加精英怪物 - if (isEliteStage) { - // 添加1-2个精英怪物 - const eliteCount = isBossStage ? 1 : Math.floor(Math.random() * 2) + 1; - for (let i = 0; i < eliteCount; i++) { - const eliteUUID = EliteMons[Math.floor(Math.random() * EliteMons.length)] || 5201; + } else { + // 普通波 + for (let i = 0; i < baseCount; i++) { + // 随机决定是否生成精英怪 + const isElite = Math.random() < eliteChance; + const monList = isElite ? eliteMons : normalMons; + const randomUuid = monList[Math.floor(Math.random() * monList.length)]; + monsterConfigs.push({ - uuid: eliteUUID, - buff: [], - level: stage, // 精英等级等于波次 - monType: MonType.ELITE + uuid: randomUuid, + type: isElite ? MonType.ELITE : MonType.NORMAL, + level: stage, + position: i % 5 }); } - - // 精英波次减少普通怪物数量 - baseMonsterCount = Math.max(1, baseMonsterCount - eliteCount); } - - // 添加普通怪物 - const remainingCount = baseMonsterCount; - for (let i = 0; i < remainingCount; i++) { - // 从普通怪物列表中随机选择一个 - const normalMonsters = getMonList(); - const normalUUID = normalMonsters.length > 0 - ? normalMonsters[Math.floor(Math.random() * normalMonsters.length)] - : 5201; - - monsterConfigs.push({ - uuid: normalUUID, - buff: [], - level: stage, // 普通怪物等级等于波次 - monType: MonType.NORMAL - }); - } - - // 判断是否生成额外怪物 - if (Math.random() < StageRule.extraMonsterRate) { - const normalMonsters = getMonList(); - const extraUUID = normalMonsters.length > 0 - ? normalMonsters[Math.floor(Math.random() * normalMonsters.length)] - : 5201; - - monsterConfigs.push({ - uuid: extraUUID, - buff: [], - level: stage, - monType: MonType.NORMAL - }); - } - + return monsterConfigs; } - - - -