refactor(monster&cast): 重构怪物移动与AOE技能目标逻辑
1. 移除固定网格站位,怪物从右侧统一出生并向左推进 2. 修改AOE技能索敌逻辑,直接使用最近敌人真实位置 3. 新增怪物自动推进与战斗停船逻辑,优化战斗体验
This commit is contained in:
@@ -4,11 +4,12 @@
|
||||
*
|
||||
* 职责:
|
||||
* 1. 管理每一波怪物的生成计划:根据 RogueConfig 生成怪物。
|
||||
* 2. 自动推进波次:在准备阶段结束时(PhasePrepareEnd)统一刷出怪物。
|
||||
* 2. 自动推进波次:在准备阶段结束时(PhasePrepareEnd)把怪物转入逐个刷出队列。
|
||||
*
|
||||
* 关键设计:
|
||||
* - 采用 12 个硬编码的网格位置点 (MON_POSITIONS,3行x4列)
|
||||
* - 每次生成最多 12 个怪物,固定在位置点。
|
||||
* - 所有怪物统一从右侧 X=400 出生点逐个刷出(MON_SPAWN_INTERVAL 节奏控制)。
|
||||
* - 实际阵型与推进由 MonMoveComp 在战斗中向左移动自然形成,不再使用固定网格点。
|
||||
* - 槽位索引(3行×4列)仅用于 monGrid 寻路与 SCastSystem 索敌定位。
|
||||
* - 上一波残留怪在波次结束/开始时统一清理。
|
||||
*/
|
||||
import { _decorator, v3, Vec3 } from "cc";
|
||||
@@ -35,25 +36,29 @@ export class MissionMonCompComp extends CCComp {
|
||||
private static readonly MAX_MONSTERS = 12;
|
||||
/** 怪物出生掉落高度 */
|
||||
private static readonly MON_DROP_HEIGHT = 0;
|
||||
/** 怪物统一从右侧 X=400 出生点逐个刷出,随后向左推进 */
|
||||
private static readonly MON_SPAWN_X = 400;
|
||||
/** 逐个刷怪间隔(秒):保证怪物排成纵队,避免堆叠 */
|
||||
private static readonly MON_SPAWN_INTERVAL = 0.3;
|
||||
|
||||
/** 硬编码的 12 个怪物占位点 (3行4列) */
|
||||
/**
|
||||
* 12 个怪物占位点:所有槽位统一以右侧出生点 (X=400) 作为坐标,
|
||||
* 实际阵型由 MonMoveComp 在战斗中向左推进时自然拉开。
|
||||
* 槽位索引仍保留 3 行 × 4 列结构,供 monGrid 寻路与 SCastSystem 索敌使用。
|
||||
*/
|
||||
public static readonly MON_POSITIONS: Vec3[] = [
|
||||
// 第 1 列 (X=60)
|
||||
v3(0, BoxSet.GAME_LINE, 0), // index 0: Top
|
||||
v3(0, BoxSet.GAME_LINE, 0), // index 1: Mid
|
||||
v3(0, BoxSet.GAME_LINE, 0), // index 2: Bot
|
||||
// 第 2 列 (X=140)
|
||||
v3(90, BoxSet.GAME_LINE, 0), // index 3: Top
|
||||
v3(90, BoxSet.GAME_LINE, 0), // index 4: Mid
|
||||
v3(90, BoxSet.GAME_LINE, 0), // index 5: Bot
|
||||
// 第 3 列 (X=220)
|
||||
v3(180, BoxSet.GAME_LINE, 0), // index 6: Top
|
||||
v3(180, BoxSet.GAME_LINE, 0), // index 7: Mid
|
||||
v3(180, BoxSet.GAME_LINE, 0), // index 8: Bot
|
||||
// 第 4 列 (X=300)
|
||||
v3(270, BoxSet.GAME_LINE, 0), // index 9: Top
|
||||
v3(270, BoxSet.GAME_LINE, 0), // index 10: Mid
|
||||
v3(270, BoxSet.GAME_LINE, 0), // index 11: Bot
|
||||
v3(MissionMonCompComp.MON_SPAWN_X, BoxSet.GAME_LINE, 0), // index 0: Col1-Top
|
||||
v3(MissionMonCompComp.MON_SPAWN_X, BoxSet.GAME_LINE, 0), // index 1: Col1-Mid
|
||||
v3(MissionMonCompComp.MON_SPAWN_X, BoxSet.GAME_LINE, 0), // index 2: Col1-Bot
|
||||
v3(MissionMonCompComp.MON_SPAWN_X, BoxSet.GAME_LINE, 0), // index 3: Col2-Top
|
||||
v3(MissionMonCompComp.MON_SPAWN_X, BoxSet.GAME_LINE, 0), // index 4: Col2-Mid
|
||||
v3(MissionMonCompComp.MON_SPAWN_X, BoxSet.GAME_LINE, 0), // index 5: Col2-Bot
|
||||
v3(MissionMonCompComp.MON_SPAWN_X, BoxSet.GAME_LINE, 0), // index 6: Col3-Top
|
||||
v3(MissionMonCompComp.MON_SPAWN_X, BoxSet.GAME_LINE, 0), // index 7: Col3-Mid
|
||||
v3(MissionMonCompComp.MON_SPAWN_X, BoxSet.GAME_LINE, 0), // index 8: Col3-Bot
|
||||
v3(MissionMonCompComp.MON_SPAWN_X, BoxSet.GAME_LINE, 0), // index 9: Col4-Top
|
||||
v3(MissionMonCompComp.MON_SPAWN_X, BoxSet.GAME_LINE, 0), // index 10: Col4-Mid
|
||||
v3(MissionMonCompComp.MON_SPAWN_X, BoxSet.GAME_LINE, 0), // index 11: Col4-Bot
|
||||
];
|
||||
|
||||
// ======================== 编辑器属性 ========================
|
||||
@@ -71,8 +76,12 @@ export class MissionMonCompComp extends CCComp {
|
||||
private waveTargetCount: number = 0;
|
||||
/** 当前波已生成的怪物数量 */
|
||||
private waveSpawnedCount: number = 0;
|
||||
/** 等待生成的怪物队列 */
|
||||
/** 等待生成的怪物队列(波次总池) */
|
||||
private pendingMonsters: GeneratedMonster[] = [];
|
||||
/** 逐个刷怪队列:从 pendingMonsters 转入,按节奏在 update 中释放 */
|
||||
private spawnQueue: GeneratedMonster[] = [];
|
||||
/** 逐个刷怪累计计时(秒) */
|
||||
private spawnTimer: number = 0;
|
||||
|
||||
// ======================== 生命周期 ========================
|
||||
|
||||
@@ -83,7 +92,20 @@ export class MissionMonCompComp extends CCComp {
|
||||
}
|
||||
|
||||
protected update(dt: number): void {
|
||||
smc.vmdata.mission_data.pending_mon_num = this.pendingMonsters.length;
|
||||
// pending_mon_num 同时统计未刷出的总池与正在释放的队列,确保 UI 与全灭判定一致
|
||||
smc.vmdata.mission_data.pending_mon_num = this.pendingMonsters.length + this.spawnQueue.length;
|
||||
|
||||
// 逐个刷怪:按 MON_SPAWN_INTERVAL 节奏从队列释放
|
||||
if (this.spawnQueue.length > 0) {
|
||||
this.spawnTimer += dt;
|
||||
if (this.spawnTimer >= MissionMonCompComp.MON_SPAWN_INTERVAL) {
|
||||
this.spawnTimer = 0;
|
||||
const monData = this.spawnQueue.shift()!;
|
||||
const targetPosIndex = this.waveSpawnedCount % MissionMonCompComp.MAX_MONSTERS;
|
||||
this.addMonsterAtGrid(targetPosIndex, monData, this.currentWave);
|
||||
this.waveSpawnedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start() {}
|
||||
@@ -115,6 +137,8 @@ export class MissionMonCompComp extends CCComp {
|
||||
this.waveTargetCount = 0;
|
||||
this.waveSpawnedCount = 0;
|
||||
this.pendingMonsters = [];
|
||||
this.spawnQueue = [];
|
||||
this.spawnTimer = 0;
|
||||
|
||||
// 预生成第一波数据以获取数量和 Boss 信息
|
||||
const monsters = spawningEngine.generateWave(this.currentWave);
|
||||
@@ -142,24 +166,24 @@ export class MissionMonCompComp extends CCComp {
|
||||
|
||||
private onPhasePrepareEnd() {
|
||||
this.resetSlotSpawnData();
|
||||
|
||||
// 准备结束阶段,立即刷出本波所有怪物
|
||||
|
||||
// 准备结束阶段:把本波待刷怪物转入逐个释放队列,
|
||||
// 实际生成时机由 update() 按 MON_SPAWN_INTERVAL 节奏触发,
|
||||
// 让怪物从 X=400 出生点排成纵队依次向左推进。
|
||||
if (this.pendingMonsters.length > 0) {
|
||||
let count = Math.min(this.pendingMonsters.length, MissionMonCompComp.MAX_MONSTERS);
|
||||
const count = Math.min(this.pendingMonsters.length, MissionMonCompComp.MAX_MONSTERS);
|
||||
for (let i = 0; i < count; i++) {
|
||||
const monData = this.pendingMonsters.shift()!;
|
||||
const targetPosIndex = this.waveSpawnedCount % MissionMonCompComp.MAX_MONSTERS;
|
||||
this.addMonsterAtGrid(targetPosIndex, monData, this.currentWave);
|
||||
this.waveSpawnedCount++;
|
||||
this.spawnQueue.push(this.pendingMonsters.shift()!);
|
||||
}
|
||||
this.pendingMonsters = [];
|
||||
// 让首个怪物在下一帧立即刷出,避免额外延迟
|
||||
this.spawnTimer = MissionMonCompComp.MON_SPAWN_INTERVAL;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 槽位管理 ========================
|
||||
|
||||
/**
|
||||
* 清理上一波残留怪物,并重置生成计数
|
||||
* 清理上一波残留怪物,并重置生成计数与逐个刷怪队列
|
||||
*/
|
||||
private resetSlotSpawnData() {
|
||||
ecs.query(ecs.allOf(HeroAttrsComp)).forEach(e => {
|
||||
@@ -168,8 +192,11 @@ export class MissionMonCompComp extends CCComp {
|
||||
e.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
this.waveSpawnedCount = 0;
|
||||
// 同步丢弃上一波未释放的队列,避免与新一波混合
|
||||
this.spawnQueue = [];
|
||||
this.spawnTimer = 0;
|
||||
}
|
||||
|
||||
// ======================== 怪物生成 ========================
|
||||
|
||||
Reference in New Issue
Block a user