feat(地图): 新增波次怪物占位配置系统
- 引入 WaveSlotConfig 和 DefaultWaveSlot 配置,支持每波怪物类型和数量自定义 - 替换硬编码的槽位数量,根据配置动态计算槽位总数和类型分布 - 重构怪物分配逻辑,依据怪物类型匹配配置槽位类型
This commit is contained in:
@@ -8,7 +8,7 @@ import { HeroInfo, HType } from "../common/config/heroSet";
|
|||||||
import { smc } from "../common/SingletonModuleComp";
|
import { smc } from "../common/SingletonModuleComp";
|
||||||
import { GameEvent } from "../common/config/GameEvent";
|
import { GameEvent } from "../common/config/GameEvent";
|
||||||
import {BoxSet } from "../common/config/GameSet";
|
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 { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||||
import { MoveComp } from "../hero/MoveComp";
|
import { MoveComp } from "../hero/MoveComp";
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
@@ -18,8 +18,6 @@ const { ccclass, property } = _decorator;
|
|||||||
@ecs.register('MissionMonComp', false)
|
@ecs.register('MissionMonComp', false)
|
||||||
export class MissionMonCompComp extends CCComp {
|
export class MissionMonCompComp extends CCComp {
|
||||||
private static readonly BOSS_RENDER_PRIORITY = 1000000;
|
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_START_X = 30;
|
||||||
private static readonly MON_SLOT_X_INTERVAL = 60;
|
private static readonly MON_SLOT_X_INTERVAL = 60;
|
||||||
private static readonly MON_DROP_HEIGHT = 280;
|
private static readonly MON_DROP_HEIGHT = 280;
|
||||||
@@ -48,7 +46,7 @@ export class MissionMonCompComp extends CCComp {
|
|||||||
monLv: number,
|
monLv: number,
|
||||||
}>> = [];
|
}>> = [];
|
||||||
private slotOccupiedEids: Array<number | null> = [];
|
private slotOccupiedEids: Array<number | null> = [];
|
||||||
private slotRangeTypes: Array<HType.Melee | HType.Long> = [];
|
private slotRangeTypes: Array<number> = [];
|
||||||
/** 全局生成顺序计数器,用于层级管理(预留) */
|
/** 全局生成顺序计数器,用于层级管理(预留) */
|
||||||
private globalSpawnOrder: number = 0;
|
private globalSpawnOrder: number = 0;
|
||||||
/** 插队刷怪处理计时器 */
|
/** 插队刷怪处理计时器 */
|
||||||
@@ -61,7 +59,7 @@ export class MissionMonCompComp extends CCComp {
|
|||||||
onLoad(){
|
onLoad(){
|
||||||
this.on(GameEvent.FightReady,this.fight_ready,this)
|
this.on(GameEvent.FightReady,this.fight_ready,this)
|
||||||
this.on("SpawnSpecialMonster", this.onSpawnSpecialMonster, 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.waveSpawnedCount = 0
|
||||||
this.bossSpawnedInWave = false
|
this.bossSpawnedInWave = false
|
||||||
this.MonQueue = []
|
this.MonQueue = []
|
||||||
this.resetSlotSpawnData()
|
|
||||||
this.startNextWave()
|
this.startNextWave()
|
||||||
mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] Starting Wave System");
|
mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] Starting Wave System");
|
||||||
}
|
}
|
||||||
@@ -150,7 +147,7 @@ export class MissionMonCompComp extends CCComp {
|
|||||||
this.waveSpawnedCount = 0;
|
this.waveSpawnedCount = 0;
|
||||||
this.bossSpawnedInWave = false;
|
this.bossSpawnedInWave = false;
|
||||||
this.waveSpawnTimer = this.waveSpawnCd;
|
this.waveSpawnTimer = this.waveSpawnCd;
|
||||||
this.confirmWaveSlotTypes();
|
this.resetSlotSpawnData(this.currentWave);
|
||||||
this.primeWaveInitialBurst();
|
this.primeWaveInitialBurst();
|
||||||
oops.message.dispatchEvent(GameEvent.NewWave, {
|
oops.message.dispatchEvent(GameEvent.NewWave, {
|
||||||
wave: this.currentWave,
|
wave: this.currentWave,
|
||||||
@@ -216,7 +213,7 @@ export class MissionMonCompComp extends CCComp {
|
|||||||
private primeWaveInitialBurst() {
|
private primeWaveInitialBurst() {
|
||||||
const remain = this.waveTargetCount - this.waveSpawnedCount;
|
const remain = this.waveTargetCount - this.waveSpawnedCount;
|
||||||
if (remain <= 0) return;
|
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++) {
|
for (let i = 0; i < burstCount; i++) {
|
||||||
const uuid = this.getRandomNormalMonsterUuid();
|
const uuid = this.getRandomNormalMonsterUuid();
|
||||||
const upType = this.getRandomUpType();
|
const upType = this.getRandomUpType();
|
||||||
@@ -225,23 +222,32 @@ export class MissionMonCompComp extends CCComp {
|
|||||||
this.waveSpawnedCount += burstCount;
|
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(
|
this.slotSpawnQueues = Array.from(
|
||||||
{ length: MissionMonCompComp.MON_SLOT_COUNT },
|
{ length: totalSlots },
|
||||||
() => []
|
() => []
|
||||||
);
|
);
|
||||||
this.slotOccupiedEids = Array.from(
|
this.slotOccupiedEids = Array.from(
|
||||||
{ length: MissionMonCompComp.MON_SLOT_COUNT },
|
{ length: totalSlots },
|
||||||
() => null
|
() => null
|
||||||
);
|
);
|
||||||
this.confirmWaveSlotTypes();
|
this.confirmWaveSlotTypes(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
private confirmWaveSlotTypes() {
|
private confirmWaveSlotTypes(config: IWaveSlot[]) {
|
||||||
this.slotRangeTypes = Array.from(
|
this.slotRangeTypes = [];
|
||||||
{ length: MissionMonCompComp.MON_SLOT_COUNT },
|
for (const slot of config) {
|
||||||
(_, index) => index < MissionMonCompComp.MON_FRONT_SLOT_COUNT ? HType.Melee : HType.Long
|
for (let i = 0; i < slot.count; i++) {
|
||||||
);
|
this.slotRangeTypes.push(slot.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private hasPendingSlotQueue() {
|
private hasPendingSlotQueue() {
|
||||||
@@ -279,44 +285,40 @@ export class MissionMonCompComp extends CCComp {
|
|||||||
return occupied + this.slotSpawnQueues[slotIndex].length;
|
return occupied + this.slotSpawnQueues[slotIndex].length;
|
||||||
}
|
}
|
||||||
|
|
||||||
private resolveMonsterSlotRange(uuid: number): HType.Melee | HType.Long {
|
private resolveMonType(uuid: number): number {
|
||||||
const type = HeroInfo[uuid]?.type;
|
for (const key in MonList) {
|
||||||
if (type === HType.Melee) return HType.Melee;
|
const list = MonList[key as unknown as number] as number[];
|
||||||
return HType.Long;
|
if (list && list.includes(uuid)) {
|
||||||
}
|
return Number(key);
|
||||||
|
}
|
||||||
private resolveSlotPriorityIndexes(uuid: number): number[] {
|
|
||||||
if (this.resolveMonsterSlotRange(uuid) === HType.Melee) {
|
|
||||||
return [0, 1, 2, 3, 4, 5];
|
|
||||||
}
|
}
|
||||||
return [5, 4, 3, 2, 1, 0];
|
return MonType.Melee;
|
||||||
}
|
}
|
||||||
|
|
||||||
private pickAssignSlotIndex(uuid: number): number {
|
private pickAssignSlotIndex(uuid: number): number {
|
||||||
const expectedRange = this.resolveMonsterSlotRange(uuid);
|
const expectedType = this.resolveMonType(uuid);
|
||||||
const slotPriority = this.resolveSlotPriorityIndexes(uuid);
|
|
||||||
let bestLoad = Number.MAX_SAFE_INTEGER;
|
let bestLoad = Number.MAX_SAFE_INTEGER;
|
||||||
let bestIndex = -1;
|
let bestIndex = -1;
|
||||||
for (let i = 0; i < slotPriority.length; i++) {
|
|
||||||
const index = slotPriority[i];
|
for (let i = 0; i < this.slotRangeTypes.length; i++) {
|
||||||
if (this.slotRangeTypes[index] !== expectedRange) continue;
|
if (this.slotRangeTypes[i] !== expectedType) continue;
|
||||||
const load = this.getSlotQueueLoad(index);
|
const load = this.getSlotQueueLoad(i);
|
||||||
if (load < bestLoad) {
|
if (load < bestLoad) {
|
||||||
bestLoad = load;
|
bestLoad = load;
|
||||||
bestIndex = index;
|
bestIndex = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bestIndex >= 0) return bestIndex;
|
if (bestIndex >= 0) return bestIndex;
|
||||||
for (let i = 0; i < slotPriority.length; i++) {
|
|
||||||
const index = slotPriority[i];
|
for (let i = 0; i < this.slotRangeTypes.length; i++) {
|
||||||
const load = this.getSlotQueueLoad(index);
|
const load = this.getSlotQueueLoad(i);
|
||||||
if (load < bestLoad) {
|
if (load < bestLoad) {
|
||||||
bestLoad = load;
|
bestLoad = load;
|
||||||
bestIndex = index;
|
bestIndex = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bestIndex >= 0) return bestIndex;
|
return Math.max(0, bestIndex);
|
||||||
return bestIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private enqueueMonsterRequest(
|
private enqueueMonsterRequest(
|
||||||
|
|||||||
@@ -35,3 +35,38 @@ export const MonList = {
|
|||||||
export const BossList = [6006,6104,6015]
|
export const BossList = [6006,6104,6015]
|
||||||
export const SpawnPowerBias = 1
|
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 }
|
||||||
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user