2 Commits

Author SHA1 Message Date
panw
f678d52ffb feat(map): 引入任务阶段状态机重构战斗流程
- 新增 MissionPhase 枚举定义任务生命周期各阶段
- 实现 changePhase 方法统一管理阶段切换逻辑与事件触发
- 重构 to_fight、enterPreparePhase 等方法使用状态机驱动
- 调整战斗开始/结束逻辑以适配新的阶段状态
- 启用调试模式便于开发阶段问题排查
2026-04-14 09:43:48 +08:00
panw
05ce0a0b8c fix: 为牧师英雄添加缺失的fstart和fend属性
添加fstart和fend属性以修复牧师英雄的技能配置,确保其技能6302能正确关联和生效。
2026-04-14 08:46:43 +08:00
3 changed files with 135 additions and 31 deletions

View File

@@ -131,7 +131,7 @@ export const HeroInfo: Record<number, heroInfo> = {
skills:{6011:{uuid:6101,lv:1,cd:0.9,ccd:0},6101:{uuid:6101,lv:1,cd:5,ccd:0}},info:"暴射,光箭 远dps"},
// ========== 腐竹英雄 ==========
5301:{uuid:5301,name:"牧师",path:"hh1", fac:FacSet.HERO,cards_lv:1,lv:1,type:HType.Long,hp:150,ap:20,speed:800,
5301:{uuid:5301,name:"牧师",path:"hh1", fac:FacSet.HERO,cards_lv:1,lv:1,type:HType.Long,hp:150,ap:20,speed:800,fstart:6302,fend:6302,
skills:{6202:{uuid:6202,lv:1,cd:1.2,ccd:0},6302:{uuid:6302,lv:1,cd:5,ccd:0}},info:"冰锥1,治疗 远辅助" },
5302:{uuid:5302,name:"战地医师",path:"hz1", fac:FacSet.HERO,cards_lv:2,lv:1,type:HType.Long,hp:300,ap:40,speed:800,
skills:{6202:{uuid:6202,lv:1,cd:1.2,ccd:0},6304:{uuid:6304,lv:1,cd:5,ccd:0}},info:"冰锥1,群体治疗 远辅助"},

View File

@@ -0,0 +1,11 @@
{
"ver": "1.0.1",
"importer": "text",
"imported": true,
"uuid": "628b9fbc-1df1-453e-bf5f-d51afce3e2f4",
"files": [
".json"
],
"subMetas": {},
"userData": {}
}

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,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.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);
}