feat(战斗): 实现战斗时间结束和怪物全灭自动推进波次
- 将战斗时间从600秒改为30秒,便于测试 - 战斗倒计时归零或场上怪物全灭时,自动结束当前波次并进入准备阶段 - 怪物波次切换时,新怪物继承被覆盖旧怪物的部分属性(生命值和攻击力) - 调整波次初始化逻辑,确保战斗时间在每波开始时重置 - 新增事件 PhasePrepareEnd 和 TimeUpAdvanceWave 协调阶段切换
This commit is contained in:
@@ -103,6 +103,8 @@ export class MissionMonCompComp extends CCComp {
|
||||
onLoad(){
|
||||
this.on(GameEvent.FightReady,this.fight_ready,this)
|
||||
this.on("SpawnSpecialMonster", this.onSpawnSpecialMonster, this);
|
||||
this.on("PhasePrepareEnd", this.onPhasePrepareEnd, this);
|
||||
this.on("TimeUpAdvanceWave", this.onTimeUpAdvanceWave, this);
|
||||
this.resetSlotSpawnData(1)
|
||||
}
|
||||
|
||||
@@ -119,7 +121,6 @@ export class MissionMonCompComp extends CCComp {
|
||||
if(smc.mission.stop_mon_action) return;
|
||||
if(!smc.mission.in_fight) return;
|
||||
this.refreshSlotOccupancy();
|
||||
this.tryAdvanceWave();
|
||||
if(!smc.mission.in_fight) return;
|
||||
if(smc.mission.stop_spawn_mon) return;
|
||||
this.updateSpecialQueue(dt);
|
||||
@@ -154,11 +155,25 @@ export class MissionMonCompComp extends CCComp {
|
||||
smc.mission.stop_spawn_mon = false
|
||||
this.globalSpawnOrder = 0
|
||||
this.queueTimer = 0
|
||||
this.currentWave = 0
|
||||
this.currentWave = 1
|
||||
this.waveTargetCount = 0
|
||||
this.waveSpawnedCount = 0
|
||||
this.MonQueue = []
|
||||
this.startNextWave()
|
||||
|
||||
let hasBoss = false;
|
||||
const config = WaveSlotConfig[this.currentWave] || DefaultWaveSlot;
|
||||
for (const slot of config) {
|
||||
if (slot.type === MonType.MeleeBoss || slot.type === MonType.LongBoss) {
|
||||
hasBoss = true;
|
||||
}
|
||||
}
|
||||
oops.message.dispatchEvent(GameEvent.NewWave, {
|
||||
wave: this.currentWave,
|
||||
total: this.waveTargetCount,
|
||||
bossWave: hasBoss,
|
||||
});
|
||||
|
||||
// 不再直接调用 startNextWave(),等待进入 PrepareEnd 阶段再刷怪
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] Starting Wave System");
|
||||
}
|
||||
|
||||
@@ -224,10 +239,9 @@ export class MissionMonCompComp extends CCComp {
|
||||
* 2. 重置槽位并根据配置生成本波所有怪物。
|
||||
* 3. 分发 NewWave 事件。
|
||||
*/
|
||||
private startNextWave() {
|
||||
private onTimeUpAdvanceWave() {
|
||||
this.currentWave += 1;
|
||||
smc.vmdata.mission_data.level = this.currentWave;
|
||||
this.resetSlotSpawnData(this.currentWave);
|
||||
|
||||
// 检查本波是否有 Boss
|
||||
let hasBoss = false;
|
||||
@@ -240,20 +254,13 @@ export class MissionMonCompComp extends CCComp {
|
||||
|
||||
oops.message.dispatchEvent(GameEvent.NewWave, {
|
||||
wave: this.currentWave,
|
||||
total: this.waveTargetCount,
|
||||
total: this.waveTargetCount, // 此时还是上一波的怪物数量,但可以不传或后续修正
|
||||
bossWave: hasBoss,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试推进波次:
|
||||
* 条件:队列为空 + 所有槽位无活怪 + 全局怪物数为 0。
|
||||
*/
|
||||
private tryAdvanceWave() {
|
||||
if (this.MonQueue.length > 0) return;
|
||||
if (this.hasActiveSlotMonster()) return;
|
||||
if (smc.vmdata.mission_data.mon_num > 0) return;
|
||||
this.startNextWave();
|
||||
private onPhasePrepareEnd() {
|
||||
this.resetSlotSpawnData(this.currentWave);
|
||||
}
|
||||
|
||||
/** 获取当前阶段(stage = wave - 1,用于属性成长计算) */
|
||||
@@ -316,6 +323,7 @@ export class MissionMonCompComp extends CCComp {
|
||||
*/
|
||||
private resetSlotSpawnData(wave: number = 1) {
|
||||
const config: IWaveSlot[] = WaveSlotConfig[wave] || DefaultWaveSlot;
|
||||
const oldOccupiedEids = [...this.slotOccupiedEids];
|
||||
this.slotOccupiedEids = Array(MissionMonCompComp.MAX_SLOTS).fill(null);
|
||||
|
||||
let allMons: any[] = [];
|
||||
@@ -368,11 +376,49 @@ export class MissionMonCompComp extends CCComp {
|
||||
}
|
||||
}
|
||||
|
||||
let absorbedEids = new Set<number>();
|
||||
|
||||
// 立即生成本波所有怪物
|
||||
for (let i = 0; i < MissionMonCompComp.MAX_SLOTS; i++) {
|
||||
const req = assignedSlots[i];
|
||||
if (req && req !== "occupied") {
|
||||
this.addMonsterBySlot(i, req.uuid, req.isBoss, req.upType, req.monLv, req.slotsPerMon);
|
||||
let inheritedHp = 0;
|
||||
let inheritedAp = 0;
|
||||
|
||||
for (let j = 0; j < req.slotsPerMon; j++) {
|
||||
let oldEid = oldOccupiedEids[i + j];
|
||||
if (oldEid && !absorbedEids.has(oldEid)) {
|
||||
absorbedEids.add(oldEid);
|
||||
const entity = ecs.getEntityByEid(oldEid);
|
||||
if (entity) {
|
||||
const attrs = entity.get(HeroAttrsComp);
|
||||
if (attrs && attrs.hp > 0 && !attrs.is_dead) {
|
||||
inheritedHp += attrs.hp;
|
||||
inheritedAp += Math.floor(attrs.ap / 2);
|
||||
}
|
||||
entity.destroy();
|
||||
}
|
||||
}
|
||||
oldOccupiedEids[i + j] = null;
|
||||
}
|
||||
|
||||
this.addMonsterBySlot(i, req.uuid, req.isBoss, req.upType, req.monLv, req.slotsPerMon, inheritedHp, inheritedAp);
|
||||
}
|
||||
}
|
||||
|
||||
// 清理被覆盖但没有被新怪占用槽位的旧怪(或者保留它们)
|
||||
// 按照需求,保留未被覆盖的旧怪物
|
||||
for (let i = 0; i < MissionMonCompComp.MAX_SLOTS; i++) {
|
||||
if (oldOccupiedEids[i]) {
|
||||
const entity = ecs.getEntityByEid(oldOccupiedEids[i]!);
|
||||
if (entity) {
|
||||
const attrs = entity.get(HeroAttrsComp);
|
||||
if (attrs && attrs.hp > 0 && !attrs.is_dead) {
|
||||
this.slotOccupiedEids[i] = oldOccupiedEids[i];
|
||||
} else {
|
||||
entity.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -430,6 +476,8 @@ export class MissionMonCompComp extends CCComp {
|
||||
upType: UpType = UpType.AP1_HP1,
|
||||
monLv: number = 1,
|
||||
slotsPerMon: number = 1,
|
||||
inheritedHp: number = 0,
|
||||
inheritedAp: number = 0,
|
||||
) {
|
||||
let mon = ecs.getEntity<Monster>(Monster);
|
||||
let scale = -1;
|
||||
@@ -464,8 +512,8 @@ export class MissionMonCompComp extends CCComp {
|
||||
const stage = this.getCurrentStage();
|
||||
const grow = this.resolveGrowPair(upType, isBoss);
|
||||
const bias = Math.max(0.1, this.getSpawnPowerBias());
|
||||
model.ap = Math.max(1, Math.floor((base.ap + stage * grow[0]) * bias));
|
||||
model.hp_max = Math.max(1, Math.floor((base.hp + stage * grow[1]) * bias));
|
||||
model.ap = Math.max(1, Math.floor((base.ap + stage * grow[0]) * bias)) + inheritedAp;
|
||||
model.hp_max = Math.max(1, Math.floor((base.hp + stage * grow[1]) * bias)) + inheritedHp;
|
||||
model.hp = model.hp_max;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user