From eb106c1b60ad29de9d2857cfb6c12f64e7771404 Mon Sep 17 00:00:00 2001 From: panw Date: Fri, 3 Apr 2026 16:34:29 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=9C=B0=E5=9B=BE):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=B3=A2=E6=AC=A1=E6=80=AA=E7=89=A9=E5=8D=A0=E4=BD=8D=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入 WaveSlotConfig 和 DefaultWaveSlot 配置,支持每波怪物类型和数量自定义 - 替换硬编码的槽位数量,根据配置动态计算槽位总数和类型分布 - 重构怪物分配逻辑,依据怪物类型匹配配置槽位类型 --- assets/script/game/map/MissionMonComp.ts | 82 ++++++++++++------------ assets/script/game/map/RogueConfig.ts | 35 ++++++++++ 2 files changed, 77 insertions(+), 40 deletions(-) diff --git a/assets/script/game/map/MissionMonComp.ts b/assets/script/game/map/MissionMonComp.ts index b483021e..2e2b0b5b 100644 --- a/assets/script/game/map/MissionMonComp.ts +++ b/assets/script/game/map/MissionMonComp.ts @@ -8,7 +8,7 @@ import { HeroInfo, HType } from "../common/config/heroSet"; import { smc } from "../common/SingletonModuleComp"; import { GameEvent } from "../common/config/GameEvent"; import {BoxSet } from "../common/config/GameSet"; -import { BossList, MonList, MonType, SpawnPowerBias, StageBossGrow, StageGrow, UpType } from "./RogueConfig"; +import { BossList, MonList, MonType, SpawnPowerBias, StageBossGrow, StageGrow, UpType, WaveSlotConfig, DefaultWaveSlot, IWaveSlot } from "./RogueConfig"; import { HeroAttrsComp } from "../hero/HeroAttrsComp"; import { MoveComp } from "../hero/MoveComp"; const { ccclass, property } = _decorator; @@ -18,8 +18,6 @@ const { ccclass, property } = _decorator; @ecs.register('MissionMonComp', false) export class MissionMonCompComp extends CCComp { private static readonly BOSS_RENDER_PRIORITY = 1000000; - private static readonly MON_SLOT_COUNT = 6; - private static readonly MON_FRONT_SLOT_COUNT = 3; private static readonly MON_SLOT_START_X = 30; private static readonly MON_SLOT_X_INTERVAL = 60; private static readonly MON_DROP_HEIGHT = 280; @@ -48,7 +46,7 @@ export class MissionMonCompComp extends CCComp { monLv: number, }>> = []; private slotOccupiedEids: Array = []; - private slotRangeTypes: Array = []; + private slotRangeTypes: Array = []; /** 全局生成顺序计数器,用于层级管理(预留) */ private globalSpawnOrder: number = 0; /** 插队刷怪处理计时器 */ @@ -61,7 +59,7 @@ export class MissionMonCompComp extends CCComp { onLoad(){ this.on(GameEvent.FightReady,this.fight_ready,this) this.on("SpawnSpecialMonster", this.onSpawnSpecialMonster, this); - this.resetSlotSpawnData() + this.resetSlotSpawnData(1) } /** @@ -93,7 +91,6 @@ export class MissionMonCompComp extends CCComp { this.waveSpawnedCount = 0 this.bossSpawnedInWave = false this.MonQueue = [] - this.resetSlotSpawnData() this.startNextWave() mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] Starting Wave System"); } @@ -150,7 +147,7 @@ export class MissionMonCompComp extends CCComp { this.waveSpawnedCount = 0; this.bossSpawnedInWave = false; this.waveSpawnTimer = this.waveSpawnCd; - this.confirmWaveSlotTypes(); + this.resetSlotSpawnData(this.currentWave); this.primeWaveInitialBurst(); oops.message.dispatchEvent(GameEvent.NewWave, { wave: this.currentWave, @@ -216,7 +213,7 @@ export class MissionMonCompComp extends CCComp { private primeWaveInitialBurst() { const remain = this.waveTargetCount - this.waveSpawnedCount; if (remain <= 0) return; - const burstCount = Math.min(MissionMonCompComp.MON_SLOT_COUNT, remain); + const burstCount = Math.min(this.slotSpawnQueues.length, remain); for (let i = 0; i < burstCount; i++) { const uuid = this.getRandomNormalMonsterUuid(); const upType = this.getRandomUpType(); @@ -225,23 +222,32 @@ export class MissionMonCompComp extends CCComp { this.waveSpawnedCount += burstCount; } - private resetSlotSpawnData() { + private resetSlotSpawnData(wave: number = 1) { + const config: IWaveSlot[] = WaveSlotConfig[wave] || DefaultWaveSlot; + + let totalSlots = 0; + for (const slot of config) { + totalSlots += slot.count; + } + this.slotSpawnQueues = Array.from( - { length: MissionMonCompComp.MON_SLOT_COUNT }, + { length: totalSlots }, () => [] ); this.slotOccupiedEids = Array.from( - { length: MissionMonCompComp.MON_SLOT_COUNT }, + { length: totalSlots }, () => null ); - this.confirmWaveSlotTypes(); + this.confirmWaveSlotTypes(config); } - private confirmWaveSlotTypes() { - this.slotRangeTypes = Array.from( - { length: MissionMonCompComp.MON_SLOT_COUNT }, - (_, index) => index < MissionMonCompComp.MON_FRONT_SLOT_COUNT ? HType.Melee : HType.Long - ); + private confirmWaveSlotTypes(config: IWaveSlot[]) { + this.slotRangeTypes = []; + for (const slot of config) { + for (let i = 0; i < slot.count; i++) { + this.slotRangeTypes.push(slot.type); + } + } } private hasPendingSlotQueue() { @@ -279,44 +285,40 @@ export class MissionMonCompComp extends CCComp { return occupied + this.slotSpawnQueues[slotIndex].length; } - private resolveMonsterSlotRange(uuid: number): HType.Melee | HType.Long { - const type = HeroInfo[uuid]?.type; - if (type === HType.Melee) return HType.Melee; - return HType.Long; - } - - private resolveSlotPriorityIndexes(uuid: number): number[] { - if (this.resolveMonsterSlotRange(uuid) === HType.Melee) { - return [0, 1, 2, 3, 4, 5]; + private resolveMonType(uuid: number): number { + for (const key in MonList) { + const list = MonList[key as unknown as number] as number[]; + if (list && list.includes(uuid)) { + return Number(key); + } } - return [5, 4, 3, 2, 1, 0]; + return MonType.Melee; } private pickAssignSlotIndex(uuid: number): number { - const expectedRange = this.resolveMonsterSlotRange(uuid); - const slotPriority = this.resolveSlotPriorityIndexes(uuid); + const expectedType = this.resolveMonType(uuid); let bestLoad = Number.MAX_SAFE_INTEGER; let bestIndex = -1; - for (let i = 0; i < slotPriority.length; i++) { - const index = slotPriority[i]; - if (this.slotRangeTypes[index] !== expectedRange) continue; - const load = this.getSlotQueueLoad(index); + + for (let i = 0; i < this.slotRangeTypes.length; i++) { + if (this.slotRangeTypes[i] !== expectedType) continue; + const load = this.getSlotQueueLoad(i); if (load < bestLoad) { bestLoad = load; - bestIndex = index; + bestIndex = i; } } + if (bestIndex >= 0) return bestIndex; - for (let i = 0; i < slotPriority.length; i++) { - const index = slotPriority[i]; - const load = this.getSlotQueueLoad(index); + + for (let i = 0; i < this.slotRangeTypes.length; i++) { + const load = this.getSlotQueueLoad(i); if (load < bestLoad) { bestLoad = load; - bestIndex = index; + bestIndex = i; } } - if (bestIndex >= 0) return bestIndex; - return bestIndex; + return Math.max(0, bestIndex); } private enqueueMonsterRequest( diff --git a/assets/script/game/map/RogueConfig.ts b/assets/script/game/map/RogueConfig.ts index a03ad5ca..22af7b41 100644 --- a/assets/script/game/map/RogueConfig.ts +++ b/assets/script/game/map/RogueConfig.ts @@ -35,3 +35,38 @@ export const MonList = { export const BossList = [6006,6104,6015] export const SpawnPowerBias = 1 +export interface IWaveSlot { + type: number; // 对应 MonType + count: number; +} + +// 每波怪物占位数量配置:数组顺序即为占位从左到右的排列顺序 +export const WaveSlotConfig: { [wave: number]: IWaveSlot[] } = { + 1: [ + { type: MonType.Melee, count: 2 }, + { type: MonType.Long, count: 2 } + ], + 2: [ + { type: MonType.Melee, count: 2 }, + { type: MonType.Long, count: 3 }, + { type: MonType.Support, count: 1 } + ], + 3: [ + { type: MonType.Melee, count: 3 }, + { type: MonType.MeleeBoss, count: 1 }, + { type: MonType.Long, count: 2 } + ], + 4: [ + { type: MonType.Melee, count: 2 }, + { type: MonType.Long, count: 2 }, + { type: MonType.Support, count: 1 }, + { type: MonType.LongBoss, count: 1 } + ], +} + +// 默认占位配置 (如果在 WaveSlotConfig 中找不到波次,则使用此配置) +export const DefaultWaveSlot: IWaveSlot[] = [ + { type: MonType.Melee, count: 3 }, + { type: MonType.Long, count: 3 } +] +