feat(map): 新增分段刷怪机制并调整教程波次怪物数量
1. 调整教程专用蓝图模板的近战怪生成数量从5个改为2个,并同步更新文档说明 2. 为刷怪组件添加三段式分段刷怪逻辑,每阶段间添加延迟,优化刷怪节奏 3. 重构波次初始化逻辑,提取为setupWaveData方法减少重复代码
This commit is contained in:
@@ -22,26 +22,26 @@
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 272
|
||||
"__id__": 276
|
||||
},
|
||||
{
|
||||
"__id__": 281
|
||||
"__id__": 285
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 293
|
||||
},
|
||||
{
|
||||
"__id__": 295
|
||||
},
|
||||
{
|
||||
"__id__": 297
|
||||
},
|
||||
{
|
||||
"__id__": 299
|
||||
},
|
||||
{
|
||||
"__id__": 301
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 299
|
||||
"__id__": 303
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -93,18 +93,18 @@
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 265
|
||||
},
|
||||
{
|
||||
"__id__": 267
|
||||
},
|
||||
{
|
||||
"__id__": 269
|
||||
},
|
||||
{
|
||||
"__id__": 271
|
||||
},
|
||||
{
|
||||
"__id__": 273
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 271
|
||||
"__id__": 275
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -6095,28 +6095,89 @@
|
||||
"__id__": 1
|
||||
},
|
||||
"mountedChildren": [],
|
||||
"mountedComponents": [],
|
||||
"propertyOverrides": [
|
||||
"mountedComponents": [
|
||||
{
|
||||
"__id__": 260
|
||||
},
|
||||
{
|
||||
"__id__": 262
|
||||
},
|
||||
{
|
||||
"__id__": 263
|
||||
},
|
||||
}
|
||||
],
|
||||
"propertyOverrides": [
|
||||
{
|
||||
"__id__": 264
|
||||
},
|
||||
{
|
||||
"__id__": 266
|
||||
},
|
||||
{
|
||||
"__id__": 267
|
||||
},
|
||||
{
|
||||
"__id__": 268
|
||||
}
|
||||
],
|
||||
"removedComponents": []
|
||||
},
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"__type__": "cc.MountedComponentsInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 261
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"__id__": 262
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.TargetInfo",
|
||||
"localID": [
|
||||
"f1ya2LoYBB547vP13Ydezp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Widget",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {
|
||||
"mountedRoot": {
|
||||
"__id__": 257
|
||||
}
|
||||
},
|
||||
"node": {
|
||||
"__id__": 257
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 263
|
||||
},
|
||||
"_alignFlags": 2,
|
||||
"_target": null,
|
||||
"_left": 0,
|
||||
"_right": 0,
|
||||
"_top": 0,
|
||||
"_bottom": 0,
|
||||
"_horizontalCenter": 0,
|
||||
"_verticalCenter": 0,
|
||||
"_isAbsLeft": true,
|
||||
"_isAbsRight": true,
|
||||
"_isAbsTop": true,
|
||||
"_isAbsBottom": true,
|
||||
"_isAbsHorizontalCenter": true,
|
||||
"_isAbsVerticalCenter": true,
|
||||
"_originalWidth": 0,
|
||||
"_originalHeight": 0,
|
||||
"_alignMode": 2,
|
||||
"_lockFlags": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "bcCrVWMRBOaLOq1wdUZD1Y"
|
||||
},
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 265
|
||||
},
|
||||
"propertyPath": [
|
||||
"_name"
|
||||
],
|
||||
@@ -6131,7 +6192,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 261
|
||||
"__id__": 265
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lpos"
|
||||
@@ -6139,14 +6200,14 @@
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -143.895,
|
||||
"y": 622.066,
|
||||
"y": 640,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 261
|
||||
"__id__": 265
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lrot"
|
||||
@@ -6162,7 +6223,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 261
|
||||
"__id__": 265
|
||||
},
|
||||
"propertyPath": [
|
||||
"_euler"
|
||||
@@ -6184,7 +6245,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 266
|
||||
"__id__": 270
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -6212,7 +6273,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 268
|
||||
"__id__": 272
|
||||
},
|
||||
"_alignFlags": 21,
|
||||
"_target": null,
|
||||
@@ -6248,7 +6309,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 270
|
||||
"__id__": 274
|
||||
},
|
||||
"home_btn": {
|
||||
"__id__": 45
|
||||
@@ -6285,14 +6346,14 @@
|
||||
"__id__": 1
|
||||
},
|
||||
"_prefab": {
|
||||
"__id__": 273
|
||||
"__id__": 277
|
||||
},
|
||||
"__editorExtras__": {}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 272
|
||||
"__id__": 276
|
||||
},
|
||||
"asset": {
|
||||
"__uuid__": "26bff847-cd29-48a5-bbfa-c3e2dbda688d",
|
||||
@@ -6300,7 +6361,7 @@
|
||||
},
|
||||
"fileId": "5a9CMsVQhKP5Y+UJfTKPbx",
|
||||
"instance": {
|
||||
"__id__": 274
|
||||
"__id__": 278
|
||||
},
|
||||
"targetOverrides": null
|
||||
},
|
||||
@@ -6313,20 +6374,20 @@
|
||||
"mountedChildren": [],
|
||||
"mountedComponents": [],
|
||||
"propertyOverrides": [
|
||||
{
|
||||
"__id__": 275
|
||||
},
|
||||
{
|
||||
"__id__": 277
|
||||
},
|
||||
{
|
||||
"__id__": 278
|
||||
},
|
||||
{
|
||||
"__id__": 279
|
||||
},
|
||||
{
|
||||
"__id__": 280
|
||||
"__id__": 281
|
||||
},
|
||||
{
|
||||
"__id__": 282
|
||||
},
|
||||
{
|
||||
"__id__": 283
|
||||
},
|
||||
{
|
||||
"__id__": 284
|
||||
}
|
||||
],
|
||||
"removedComponents": []
|
||||
@@ -6334,7 +6395,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 276
|
||||
"__id__": 280
|
||||
},
|
||||
"propertyPath": [
|
||||
"_name"
|
||||
@@ -6350,7 +6411,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 276
|
||||
"__id__": 280
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lpos"
|
||||
@@ -6365,7 +6426,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 276
|
||||
"__id__": 280
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lrot"
|
||||
@@ -6381,7 +6442,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 276
|
||||
"__id__": 280
|
||||
},
|
||||
"propertyPath": [
|
||||
"_euler"
|
||||
@@ -6396,7 +6457,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 276
|
||||
"__id__": 280
|
||||
},
|
||||
"propertyPath": [
|
||||
"_active"
|
||||
@@ -6410,14 +6471,14 @@
|
||||
"__id__": 1
|
||||
},
|
||||
"_prefab": {
|
||||
"__id__": 282
|
||||
"__id__": 286
|
||||
},
|
||||
"__editorExtras__": {}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 281
|
||||
"__id__": 285
|
||||
},
|
||||
"asset": {
|
||||
"__uuid__": "56aee962-4a5e-45ae-a779-999444d06d18",
|
||||
@@ -6425,7 +6486,7 @@
|
||||
},
|
||||
"fileId": "cboM54s0hM07XCtrpFp0/b",
|
||||
"instance": {
|
||||
"__id__": 283
|
||||
"__id__": 287
|
||||
},
|
||||
"targetOverrides": null
|
||||
},
|
||||
@@ -6438,26 +6499,26 @@
|
||||
"mountedChildren": [],
|
||||
"mountedComponents": [],
|
||||
"propertyOverrides": [
|
||||
{
|
||||
"__id__": 284
|
||||
},
|
||||
{
|
||||
"__id__": 286
|
||||
},
|
||||
{
|
||||
"__id__": 287
|
||||
},
|
||||
{
|
||||
"__id__": 288
|
||||
},
|
||||
{
|
||||
"__id__": 289
|
||||
"__id__": 290
|
||||
},
|
||||
{
|
||||
"__id__": 291
|
||||
},
|
||||
{
|
||||
"__id__": 292
|
||||
},
|
||||
{
|
||||
"__id__": 293
|
||||
},
|
||||
{
|
||||
"__id__": 295
|
||||
},
|
||||
{
|
||||
"__id__": 296
|
||||
}
|
||||
],
|
||||
"removedComponents": []
|
||||
@@ -6465,7 +6526,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 285
|
||||
"__id__": 289
|
||||
},
|
||||
"propertyPath": [
|
||||
"_name"
|
||||
@@ -6481,7 +6542,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 285
|
||||
"__id__": 289
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lpos"
|
||||
@@ -6496,7 +6557,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 285
|
||||
"__id__": 289
|
||||
},
|
||||
"propertyPath": [
|
||||
"_lrot"
|
||||
@@ -6512,7 +6573,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 285
|
||||
"__id__": 289
|
||||
},
|
||||
"propertyPath": [
|
||||
"_euler"
|
||||
@@ -6527,7 +6588,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 290
|
||||
"__id__": 294
|
||||
},
|
||||
"propertyPath": [
|
||||
"_top"
|
||||
@@ -6543,7 +6604,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 290
|
||||
"__id__": 294
|
||||
},
|
||||
"propertyPath": [
|
||||
"_alignFlags"
|
||||
@@ -6553,7 +6614,7 @@
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
"targetInfo": {
|
||||
"__id__": 290
|
||||
"__id__": 294
|
||||
},
|
||||
"propertyPath": [
|
||||
"_bottom"
|
||||
@@ -6570,7 +6631,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 294
|
||||
"__id__": 298
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -6598,7 +6659,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 296
|
||||
"__id__": 300
|
||||
},
|
||||
"_alignFlags": 45,
|
||||
"_target": null,
|
||||
@@ -6634,7 +6695,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 298
|
||||
"__id__": 302
|
||||
},
|
||||
"debugMode": false,
|
||||
"_id": ""
|
||||
@@ -6656,10 +6717,10 @@
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": [
|
||||
{
|
||||
"__id__": 281
|
||||
"__id__": 285
|
||||
},
|
||||
{
|
||||
"__id__": 272
|
||||
"__id__": 276
|
||||
},
|
||||
{
|
||||
"__id__": 257
|
||||
|
||||
@@ -98,6 +98,14 @@ export class MissionMonCompComp extends CCComp {
|
||||
private pendingMonsters: GeneratedMonster[] = [];
|
||||
/** 增量刷怪计时器 */
|
||||
private spawnTimer: number = 0;
|
||||
/** 分段刷怪阶段 (1, 2, 3) */
|
||||
private currentSpawnPhase: number = 1;
|
||||
/** 下一阶段刷怪的延迟计时器 */
|
||||
private phaseDelayTimer: number = 0;
|
||||
/** 当前阶段目标生成的怪物总数 */
|
||||
private phaseTargetCount: number = 0;
|
||||
/** 当前阶段已生成的怪物数 */
|
||||
private phaseSpawnedCount: number = 0;
|
||||
|
||||
// ======================== 生命周期 ========================
|
||||
|
||||
@@ -126,21 +134,35 @@ export class MissionMonCompComp extends CCComp {
|
||||
|
||||
if(smc.mission.stop_spawn_mon) return;
|
||||
|
||||
// 逐步刷怪逻辑
|
||||
// 逐步刷怪逻辑 (分 3 段刷出)
|
||||
if (this.pendingMonsters.length > 0) {
|
||||
// 如果当前阶段的怪物已经刷完,则进入延迟等待下一阶段
|
||||
if (this.phaseSpawnedCount >= this.phaseTargetCount && this.currentSpawnPhase < 3) {
|
||||
this.phaseDelayTimer -= dt;
|
||||
if (this.phaseDelayTimer <= 0) {
|
||||
this.currentSpawnPhase++;
|
||||
this.phaseSpawnedCount = 0;
|
||||
this.phaseTargetCount = this.currentSpawnPhase === 3 ?
|
||||
this.pendingMonsters.length :
|
||||
Math.ceil(this.pendingMonsters.length / (4 - this.currentSpawnPhase));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.spawnTimer += dt;
|
||||
// 控制刷怪速率:例如每 0.2 秒刷 1-2 只
|
||||
if (this.spawnTimer > 0.2) {
|
||||
this.spawnTimer = 0;
|
||||
// 一次出 2 只,加快进度
|
||||
for (let i = 0; i < 2; i++) {
|
||||
if (this.pendingMonsters.length === 0) break;
|
||||
if (this.pendingMonsters.length === 0 || this.phaseSpawnedCount >= this.phaseTargetCount) break;
|
||||
const monData = this.pendingMonsters.shift()!;
|
||||
const lane = this.pickBalancedLane();
|
||||
console.log(`[MissionMonComp] 准备生成怪物 UUID=${monData.uuid}, 剩余数量=${this.pendingMonsters.length}`);
|
||||
console.log(`[MissionMonComp] [Phase ${this.currentSpawnPhase}] 准备生成怪物 UUID=${monData.uuid}, 剩余数量=${this.pendingMonsters.length}`);
|
||||
this.addMonsterAt(lane, this.laneIndices[lane], monData);
|
||||
this.laneIndices[lane]++;
|
||||
this.waveSpawnedCount++;
|
||||
this.phaseSpawnedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,6 +190,32 @@ export class MissionMonCompComp extends CCComp {
|
||||
start() {
|
||||
}
|
||||
|
||||
private setupWaveData(monsters: GeneratedMonster[]) {
|
||||
this.pendingMonsters = monsters;
|
||||
smc.vmdata.mission_data.pending_mon_num = this.pendingMonsters.length;
|
||||
this.waveTargetCount = monsters.length;
|
||||
|
||||
// 初始化分段刷怪状态
|
||||
this.currentSpawnPhase = 1;
|
||||
this.phaseSpawnedCount = 0;
|
||||
// 第一段生成 1/3 的怪物
|
||||
this.phaseTargetCount = Math.ceil(this.pendingMonsters.length / 3);
|
||||
// 每段之间的延迟时间,可以根据需要调整,例如 3 秒
|
||||
this.phaseDelayTimer = 3.0;
|
||||
|
||||
let hasBoss = monsters.some(m => m.isBoss);
|
||||
|
||||
console.log(`[MissionMonComp] 波次 ${this.currentWave} 生成怪物总数: ${this.waveTargetCount}`);
|
||||
const uuids = monsters.map(m => m.uuid);
|
||||
console.log(`[MissionMonComp] 波次 ${this.currentWave} 怪物 UUID 列表:`, uuids);
|
||||
|
||||
oops.message.dispatchEvent(GameEvent.NewWave, {
|
||||
wave: this.currentWave,
|
||||
total: this.waveTargetCount,
|
||||
bossWave: hasBoss,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 战斗准备:重置所有运行时状态并开始第一波。
|
||||
*/
|
||||
@@ -186,20 +234,7 @@ export class MissionMonCompComp extends CCComp {
|
||||
|
||||
// 预生成第一波数据以获取数量和 Boss 信息
|
||||
const monsters = spawningEngine.generateWave(this.currentWave);
|
||||
this.pendingMonsters = monsters;
|
||||
smc.vmdata.mission_data.pending_mon_num = this.pendingMonsters.length;
|
||||
this.waveTargetCount = monsters.length;
|
||||
let hasBoss = monsters.some(m => m.isBoss);
|
||||
|
||||
console.log(`[MissionMonComp] 波次 ${this.currentWave} 生成怪物总数: ${this.waveTargetCount}`);
|
||||
const uuids = monsters.map(m => m.uuid);
|
||||
console.log(`[MissionMonComp] 波次 ${this.currentWave} 怪物 UUID 列表:`, uuids);
|
||||
|
||||
oops.message.dispatchEvent(GameEvent.NewWave, {
|
||||
wave: this.currentWave,
|
||||
total: this.waveTargetCount,
|
||||
bossWave: hasBoss,
|
||||
});
|
||||
this.setupWaveData(monsters);
|
||||
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] Starting Wave System");
|
||||
}
|
||||
@@ -265,20 +300,7 @@ export class MissionMonCompComp extends CCComp {
|
||||
|
||||
// 预生成新一波数据以获取数量和 Boss 信息
|
||||
const monsters = spawningEngine.generateWave(this.currentWave);
|
||||
this.pendingMonsters = monsters;
|
||||
smc.vmdata.mission_data.pending_mon_num = this.pendingMonsters.length;
|
||||
this.waveTargetCount = monsters.length;
|
||||
let hasBoss = monsters.some(m => m.isBoss);
|
||||
|
||||
console.log(`[MissionMonComp] 波次 ${this.currentWave} 生成怪物总数: ${this.waveTargetCount}`);
|
||||
const uuids = monsters.map(m => m.uuid);
|
||||
console.log(`[MissionMonComp] 波次 ${this.currentWave} 怪物 UUID 列表:`, uuids);
|
||||
|
||||
oops.message.dispatchEvent(GameEvent.NewWave, {
|
||||
wave: this.currentWave,
|
||||
total: this.waveTargetCount,
|
||||
bossWave: hasBoss,
|
||||
});
|
||||
this.setupWaveData(monsters);
|
||||
}
|
||||
|
||||
private onPhasePrepareEnd() {
|
||||
|
||||
@@ -464,7 +464,7 @@ export const BlueprintTemplates: BlueprintTemplate[] = [
|
||||
|
||||
// ---- 教程专用 ----
|
||||
{ id: "TUTORIAL", type: TemplateType.NORMAL, tierMin: 1, allowAffix: false,
|
||||
slots: [{ typePool: [MonType.Melee], countMin: 5, countMax: 5, weight: 1.0 }] },
|
||||
slots: [{ typePool: [MonType.Melee], countMin: 2, countMax: 2, weight: 1.0 }] },
|
||||
]
|
||||
|
||||
// ======================== 自适应难度配置 ========================
|
||||
|
||||
@@ -442,7 +442,7 @@ delta calculation per wave:
|
||||
|
||||
### 核心波次生成
|
||||
|
||||
- **GIVEN** 游戏开始(adaptive_factor=1.0),**WHEN** 进入 W1,**THEN** 生成 5 个 Melee 怪(T1, 无词缀),HP=120, AP=12。
|
||||
- **GIVEN** 游戏开始(adaptive_factor=1.0),**WHEN** 进入 W1,**THEN** 生成 2 个 Melee 怪(T1, 无词缀),HP=120, AP=12。
|
||||
- **GIVEN** 当前 Tier 1 W2(攀升波),**WHEN** 模板选取完成,**THEN** 模板类型为 NORMAL 或 MIXED,且模板的怪物槽位池中包含 Long 类型(cost=40)。运行 100 次抽取,Long 类型出现在槽位池中的比例为 100%。
|
||||
- **GIVEN** W6(Boss 波),**WHEN** 模板选取完成,**THEN** 模板类型为 BOSS,mandatory_slots 包含 Boss 类型,至少生成 1 个 MeleeBoss + 10-15 个普通怪。
|
||||
- **GIVEN** Tier 2 W1(REST 波),**WHEN** 模板选取完成,**THEN** 模板类型为 REST,template_modifier=0.5x。
|
||||
|
||||
Reference in New Issue
Block a user