feat(map): 引入任务阶段状态机重构战斗流程

- 新增 MissionPhase 枚举定义任务生命周期各阶段
- 实现 changePhase 方法统一管理阶段切换逻辑与事件触发
- 重构 to_fight、enterPreparePhase 等方法使用状态机驱动
- 调整战斗开始/结束逻辑以适配新的阶段状态
- 启用调试模式便于开发阶段问题排查
This commit is contained in:
panw
2026-04-14 09:43:48 +08:00
parent 05ce0a0b8c
commit f678d52ffb

View File

@@ -46,6 +46,17 @@ import { Tooltip } from "../skill/Tooltip";
import { CardInitCoins } from "../common/config/CardSet";
const { ccclass, property } = _decorator;
/** 任务(关卡)生命周期阶段 */
export enum MissionPhase {
None = 0, // 未初始化
PrepareStart = 1, // 准备开始阶段 (2s)
Prepare = 2, // 准备阶段 (等待玩家点击开始)
PrepareEnd = 3, // 准备结束阶段 (2s)
BattleStart = 4, // 战斗开始阶段 (2s)
Battle = 5, // 战斗阶段 (刷怪、战斗中)
BattleEnd = 6, // 战斗结束阶段 (2s)
Settle = 7 // 结算阶段
}
//@todo 需要关注 当boss死亡的时候的动画播放完成后需要触发事件通知 MissionComp 进行奖励处理
@@ -59,7 +70,7 @@ const { ccclass, property } = _decorator;
@ecs.register('MissionComp', false)
export class MissionComp extends CCComp {
@property({ tooltip: "是否启用调试日志" })
private debugMode: boolean = false;
private debugMode: boolean = true;
@property({ tooltip: "是否显示战斗内存观测面板" })
private showMemoryPanel: boolean = false;
@@ -133,6 +144,8 @@ export class MissionComp extends CCComp {
private currentWave: number = 0;
/** 上一次发放金币奖励的波数(防止重复发放) */
private lastPrepareCoinWave: number = 0;
/** 当前任务阶段 */
public currentPhase: MissionPhase = MissionPhase.None;
// ======================== ECS 查询匹配器(预缓存) ========================
@@ -168,7 +181,7 @@ export class MissionComp extends CCComp {
protected update(dt: number): void {
if(!smc.mission.play) return
if(smc.mission.pause) return
if(smc.mission.in_fight){
if(this.currentPhase === MissionPhase.Battle){
this.syncMonsterSpawnState(dt)
if(smc.mission.stop_mon_action) return
smc.vmdata.mission_data.fight_time+=dt
@@ -235,7 +248,7 @@ export class MissionComp extends CCComp {
this.node.active=true
this.data_init()
oops.message.dispatchEvent(GameEvent.FightReady)
this.enterPreparePhase()
this.changePhase(MissionPhase.Prepare)
let loading=this.node.parent.getChildByName("loading")
loading.active=true
this.scheduleOnce(()=>{
@@ -243,6 +256,89 @@ export class MissionComp extends CCComp {
},0.5)
}
/**
* 阶段切换核心方法(状态机)
* 处理状态流转时所需的事件触发和全局标志位修改。
* @param targetPhase 目标阶段
*/
private changePhase(targetPhase: MissionPhase) {
if (this.currentPhase === targetPhase) return;
const oldPhase = this.currentPhase;
this.currentPhase = targetPhase;
// 取消状态机内部产生的定时流转任务,防止状态错乱
this.unschedule(this.autoNextPhase);
switch (targetPhase) {
case MissionPhase.PrepareStart:
smc.mission.in_fight = false;
smc.vmdata.mission_data.in_fight = false;
smc.mission.stop_spawn_mon = true;
if (this.start_btn && this.start_btn.isValid) this.start_btn.active = false;
this.scheduleOnce(this.autoNextPhase, 2);
break;
case MissionPhase.Prepare:
if (this.start_btn && this.start_btn.isValid) this.start_btn.active = true;
break;
case MissionPhase.PrepareEnd:
if (this.start_btn && this.start_btn.isValid) this.start_btn.active = false;
this.scheduleOnce(this.autoNextPhase, 2);
break;
case MissionPhase.BattleStart:
// 触发战斗开始技能fstart
this.triggerHeroBattleSkills(true);
this.scheduleOnce(this.autoNextPhase, 2);
break;
case MissionPhase.Battle:
smc.mission.stop_spawn_mon = false;
smc.mission.in_fight = true;
smc.vmdata.mission_data.in_fight = true;
oops.message.dispatchEvent(GameEvent.FightStart);
break;
case MissionPhase.BattleEnd:
smc.mission.in_fight = false;
smc.vmdata.mission_data.in_fight = false;
smc.mission.stop_spawn_mon = true;
// 触发战斗结束技能fend
this.triggerHeroBattleSkills(false);
break;
case MissionPhase.Settle:
smc.mission.in_fight = false;
smc.vmdata.mission_data.in_fight = false;
smc.mission.stop_spawn_mon = true;
if (this.start_btn && this.start_btn.isValid) this.start_btn.active = false;
break;
case MissionPhase.None:
smc.mission.in_fight = false;
smc.vmdata.mission_data.in_fight = false;
smc.mission.stop_spawn_mon = false;
if (this.start_btn && this.start_btn.isValid) this.start_btn.active = false;
break;
}
}
/** 自动流转到下一阶段(过渡状态结束时调用) */
private autoNextPhase() {
switch (this.currentPhase) {
case MissionPhase.PrepareStart:
this.changePhase(MissionPhase.Prepare);
break;
case MissionPhase.PrepareEnd:
this.changePhase(MissionPhase.BattleStart);
break;
case MissionPhase.BattleStart:
this.changePhase(MissionPhase.Battle);
break;
}
}
/**
* 进入战斗:
* - 恢复刷怪
@@ -252,12 +348,7 @@ export class MissionComp extends CCComp {
* - 触发英雄战斗开始技能
*/
to_fight(){
smc.mission.stop_spawn_mon = false;
smc.mission.in_fight=true
smc.vmdata.mission_data.in_fight = true
if (this.start_btn && this.start_btn.isValid) this.start_btn.active = false;
oops.message.dispatchEvent(GameEvent.FightStart)
this.triggerHeroBattleSkills(true);
this.changePhase(MissionPhase.PrepareEnd);
}
/**
@@ -268,11 +359,7 @@ export class MissionComp extends CCComp {
* - 触发英雄战斗结束技能
*/
private enterPreparePhase() {
this.triggerHeroBattleSkills(false);
smc.mission.in_fight = false;
smc.vmdata.mission_data.in_fight = false
smc.mission.stop_spawn_mon = true;
if (this.start_btn && this.start_btn.isValid) this.start_btn.active = true;
this.changePhase(MissionPhase.PrepareStart);
}
/**
@@ -302,7 +389,7 @@ export class MissionComp extends CCComp {
private onStartFightBtnClick() {
if (!smc.mission.play) return;
if (smc.mission.pause) return;
if (smc.mission.in_fight) return;
if (this.currentPhase !== MissionPhase.Prepare) return;
this.to_fight();
}
@@ -316,24 +403,33 @@ export class MissionComp extends CCComp {
* @param is_hero_dead 是否因英雄全灭触发
*/
open_Victory(e:any,is_hero_dead: boolean = false){
smc.mission.pause = true;
mLogger.log(this.debugMode, 'MissionComp', " open_Victory",is_hero_dead,this.revive_times)
oops.gui.open(UIID.Victory,{
victory:false,
rewards:this.rewards,
game_data:this.game_data,
can_revive: is_hero_dead && this.revive_times > 0
})
this.changePhase(MissionPhase.BattleEnd);
// 延迟 2s 后进入结算,让 BattleEnd 阶段的表现能够播完
this.scheduleOnce(() => {
this.changePhase(MissionPhase.Settle);
smc.mission.pause = true;
mLogger.log(this.debugMode, 'MissionComp', " open_Victory",is_hero_dead,this.revive_times)
oops.gui.open(UIID.Victory,{
victory:false,
rewards:this.rewards,
game_data:this.game_data,
can_revive: is_hero_dead && this.revive_times > 0
})
}, 2);
}
/** 战斗结束:延迟清理组件和对象池 */
fight_end(){
this.changePhase(MissionPhase.BattleEnd);
this.scheduleOnce(() => {
this.changePhase(MissionPhase.Settle);
smc.mission.play=false
this.cleanComponents()
this.clearBattlePools()
}, 0.5)
}, 2)
}
/**
@@ -347,9 +443,7 @@ export class MissionComp extends CCComp {
this.unscheduleAllCallbacks();
smc.mission.play=false
smc.mission.pause = false;
smc.mission.in_fight = false;
smc.vmdata.mission_data.in_fight = false
if (this.start_btn && this.start_btn.isValid) this.start_btn.active = false;
this.changePhase(MissionPhase.None);
this.cleanComponents()
this.clearBattlePools()
this.node.active=false
@@ -372,6 +466,7 @@ export class MissionComp extends CCComp {
smc.vmdata.mission_data.mon_num=0
smc.vmdata.mission_data.level = 1
smc.vmdata.mission_data.mon_max = Math.max(1, Math.floor(this.maxMonsterCount))
this.currentPhase = MissionPhase.None;
this.currentWave = 1;
this.FightTime=FightSet.FiIGHT_TIME
this.rewards=[]
@@ -513,9 +608,7 @@ export class MissionComp extends CCComp {
private handleHeroWipe(heroCount: number) {
if (heroCount > 0) return;
if (!smc.mission.play || smc.mission.pause) return;
if (!smc.mission.in_fight) return;
smc.mission.in_fight = false;
smc.vmdata.mission_data.in_fight = false;
if (this.currentPhase !== MissionPhase.Battle) return;
this.open_Victory(null, true);
}