@@ -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 = fals e;
private debugMode : boolean = tru e;
@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 . m ission. 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 ( M issionPhase . 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,6 +403,11 @@ export class MissionComp extends CCComp {
* @param is_hero_dead 是否因英雄全灭触发
*/
open_Victory ( e :any , is_hero_dead : boolean = false ) {
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 , {
@@ -324,16 +416,20 @@ export class MissionComp extends CCComp {
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 . m ission. 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 ( M issionPhase . 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 ) ;
}