From e7b0d55e36414b903f4c494b4d7864a6960b02b2 Mon Sep 17 00:00:00 2001 From: panw Date: Wed, 8 Apr 2026 10:31:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(rogue):=20=E8=B0=83=E6=95=B4Boss=E5=8D=A0?= =?UTF-8?q?=E7=94=A8=E6=A7=BD=E4=BD=8D=E4=B8=BA3=E6=A0=BC=E5=B9=B6?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E6=B3=A2=E6=AC=A1=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将Boss默认占用槽位从2格改为3格,允许在任意连续三格空闲位置放置 - 简化波次配置,第1波改为2近战+1近战Boss,第2波改为2近战+1远程Boss - 更新怪物池配置,调整近战Boss池包含6006和6105 - 重构怪物分配逻辑,统一处理所有类型怪物的槽位分配 - 优化远程Boss的放置策略,优先从后往前寻找空闲槽位 --- assets/script/game/map/MissionMonComp.ts | 85 ++++++++++++------------ assets/script/game/map/RogueConfig.ts | 30 +++------ 2 files changed, 53 insertions(+), 62 deletions(-) diff --git a/assets/script/game/map/MissionMonComp.ts b/assets/script/game/map/MissionMonComp.ts index de124493..19660619 100644 --- a/assets/script/game/map/MissionMonComp.ts +++ b/assets/script/game/map/MissionMonComp.ts @@ -10,7 +10,7 @@ * * 关键设计: * - 全场固定 5 个槽位(索引 0-4),每个槽位占固定 X 坐标。 - * - Boss 占 2 个连续槽位,只能放在 0、2 号位。 + * - Boss 默认占 3 个连续槽位,只要有连续三格空闲即可。 * - slotOccupiedEids 记录每个槽位占用的怪物 ECS 实体 ID。 * - resetSlotSpawnData(wave) 在每波开始时读取配置,分配并立即生成所有怪物。 * - refreshSlotOccupancy() 定期检查槽位占用的实体是否仍存活,清除已死亡的占用。 @@ -177,14 +177,23 @@ export class MissionMonCompComp extends CCComp { const item = this.MonQueue[0]; const isBoss = MonList[MonType.MeleeBoss].includes(item.uuid) || MonList[MonType.LongBoss].includes(item.uuid); - const slotsPerMon = isBoss ? 2 : 1; + const isLongBoss = MonList[MonType.LongBoss].includes(item.uuid); + const slotsPerMon = isBoss ? 3 : 1; // 查找空闲槽位 let slotIndex = -1; - if (slotsPerMon === 2) { - // Boss 只能放在 0, 2(需要连续 2 格空闲) - for (const idx of [0, 2]) { - if (!this.slotOccupiedEids[idx] && !this.slotOccupiedEids[idx + 1]) { + if (slotsPerMon === 3) { + // 构造可用索引列表 + let allowedIndices = []; + for (let i = 0; i < MissionMonCompComp.MAX_SLOTS - 2; i++) { + allowedIndices.push(i); + } + // 远程 Boss 插队时优先尝试从后往前找 + if (isLongBoss) { + allowedIndices.reverse(); + } + for (const idx of allowedIndices) { + if (!this.slotOccupiedEids[idx] && !this.slotOccupiedEids[idx + 1] && !this.slotOccupiedEids[idx + 2]) { slotIndex = idx; break; } @@ -309,59 +318,53 @@ export class MissionMonCompComp extends CCComp { const config: IWaveSlot[] = WaveSlotConfig[wave] || DefaultWaveSlot; this.slotOccupiedEids = Array(MissionMonCompComp.MAX_SLOTS).fill(null); - let bosses: any[] = []; - let normals: any[] = []; + let allMons: any[] = []; - // 按类型分类 + // 解析配置 for (const slot of config) { - const slotsPerMon = slot.slotsPerMon || 1; const isBoss = slot.type === MonType.MeleeBoss || slot.type === MonType.LongBoss; + const slotsPerMon = slot.slotsPerMon || (isBoss ? 3 : 1); for (let i = 0; i < slot.count; i++) { const uuid = this.getRandomUuidByType(slot.type); const upType = this.getRandomUpType(); const req = { uuid, isBoss, upType, monLv: wave, slotsPerMon }; - if (isBoss || slotsPerMon === 2) { - bosses.push(req); - } else { - normals.push(req); - } + allMons.push(req); } } - this.waveTargetCount = bosses.length + normals.length; + this.waveTargetCount = allMons.length; this.waveSpawnedCount = 0; - // Boss 优先分配(只能放在 0, 2) - let bossAllowedIndices = [0, 2]; let assignedSlots = new Array(MissionMonCompComp.MAX_SLOTS).fill(null); - for (const boss of bosses) { + // 统一按顺序分配(根据所需格数找连续空位) + for (const mon of allMons) { let placed = false; - for (const idx of bossAllowedIndices) { - if (!assignedSlots[idx] && !assignedSlots[idx + 1]) { - assignedSlots[idx] = boss; - assignedSlots[idx + 1] = "occupied"; // 占位标记 - placed = true; - break; + + if (mon.slotsPerMon === 3) { + // 需要 3 格,占满连续的 3 格 + for (let idx = 0; idx < MissionMonCompComp.MAX_SLOTS - 2; idx++) { + if (!assignedSlots[idx] && !assignedSlots[idx + 1] && !assignedSlots[idx + 2]) { + assignedSlots[idx] = mon; + assignedSlots[idx + 1] = "occupied"; // 占位标记 + assignedSlots[idx + 2] = "occupied"; // 占位标记 + placed = true; + break; + } + } + } else { + // 只需要 1 格 + for (let idx = 0; idx < MissionMonCompComp.MAX_SLOTS; idx++) { + if (!assignedSlots[idx]) { + assignedSlots[idx] = mon; + placed = true; + break; + } } } + if (!placed) { - mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] No slot for boss!"); - } - } - - // 普通怪填充剩余空位 - for (const normal of normals) { - let placed = false; - for (let i = 0; i < MissionMonCompComp.MAX_SLOTS; i++) { - if (!assignedSlots[i]) { - assignedSlots[i] = normal; - placed = true; - break; - } - } - if (!placed) { - mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] No slot for normal monster!"); + mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] No slot for monster! uuid:", mon.uuid); } } diff --git a/assets/script/game/map/RogueConfig.ts b/assets/script/game/map/RogueConfig.ts index e11ecc84..3e6c41b2 100644 --- a/assets/script/game/map/RogueConfig.ts +++ b/assets/script/game/map/RogueConfig.ts @@ -10,7 +10,7 @@ * * 设计说明: * - 战场固定 5 个占位槽(索引 0-4)。 - * - Boss 占 2 个槽位,只能放在 0、2 号位(确保有连续 2 格)。 + * - Boss 默认占 3 个槽位,只要有连续 3 格空闲即可放置。 * - MissionMonComp 在每波开始时读取本配置,决定刷怪组合。 * * 注意: @@ -77,7 +77,7 @@ export const MonList = { [MonType.Melee]: [6001,6002,6003], // 近战怪池 [MonType.Long]: [6004,6005], // 远程怪池 [MonType.Support]: [6005], // 辅助怪池 - [MonType.MeleeBoss]:[6006,6015], // 近战 Boss 池 + [MonType.MeleeBoss]:[6006,6105], // 近战 Boss 池 [MonType.LongBoss]:[6104], // 远程 Boss 池 } @@ -109,38 +109,26 @@ export interface IWaveSlot { // - type: 怪物类型 (参考 MonType,如近战 0,远程 1,Boss 3 等)。 // - count: 该类型的怪在场上同时存在几个。 // - slotsPerMon: (可选) 单个怪物体积占用几个占位坑,默认为 1。 -// 大型 Boss 设为 2,它会跨占位降落。 +// 大型 Boss 默认设为 3,它会跨占位降落。 // // 【规则约束】: // - 全场固定 5 个槽位(索引 0-4)。 -// - Boss 固定占用 2 个位置,且只能出现在 1、3 号位(对应索引 0, 2)。 +// - Boss 默认占用 3 个位置,只要有连续 3 格即可。 // - 每波怪物总槽位占用不能超过 5。 // ========================================================================================= /** 各波次的怪物占位配置(key = 波次编号) */ export const WaveSlotConfig: { [wave: number]: IWaveSlot[] } = { - /** 第 1 波:2 近战 + 3 远程 */ + + /** 第 1 波:2 近战 + 1 近战Boss(默认占3格) */ 1: [ { type: MonType.Melee, count: 2 }, - { type: MonType.Long, count: 3 } + { type: MonType.MeleeBoss, count: 1 } ], - /** 第 2 波:2 近战 + 2 远程 + 1 辅助 */ + /** 第 2波:2 近战 + 1 远程Boss(默认占3格) */ 2: [ { type: MonType.Melee, count: 2 }, - { type: MonType.Long, count: 2 }, - { type: MonType.Support, count: 1 } - ], - /** 第 3 波:2 近战 + 1 近战Boss(占2格) + 1 远程 */ - 3: [ - { type: MonType.Melee, count: 2 }, - { type: MonType.MeleeBoss, count: 1, slotsPerMon: 2 }, - { type: MonType.Long, count: 1 } - ], - /** 第 4 波:2 近战 + 1 远程 + 1 远程Boss(占2格) */ - 4: [ - { type: MonType.Melee, count: 2 }, - { type: MonType.Long, count: 1 }, - { type: MonType.LongBoss, count: 1, slotsPerMon: 2 } + { type: MonType.LongBoss, count: 1 } ], }