import { _decorator, Vec3,Animation, instantiate, Prefab, Node, ProgressBar, Label } from "cc"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; import { smc } from "../common/SingletonModuleComp"; import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops"; import { HeroAttrsComp } from "../hero/HeroAttrsComp"; import { MonsterCost, MonType, calculateMonsterGold, getLevelExp, calculateMonsterExp, SpecialMonsterSchedule } from "./RogueConfig"; import { GameEvent } from "../common/config/GameEvent"; import { HeroViewComp } from "../hero/HeroViewComp"; import { UIID } from "../common/config/GameUIConfig"; import { SkillView } from "../skill/SkillView"; import { FightSet, CardType, FacSet } from "../common/config/GameSet"; import { mLogger } from "../common/Logger"; import { getLevelRewardType } from "../common/config/CardSet"; const { ccclass, property } = _decorator; //@todo 需要关注 当boss死亡的时候的动画播放完成后,需要触发事件,通知 MissionComp 进行奖励处理 /** 视图层对象 */ @ccclass('MissionComp') @ecs.register('MissionComp', false) export class MissionComp extends CCComp { @property({ tooltip: "是否启用调试日志" }) private debugMode: boolean = false; // VictoryComp:any = null; // reward:number = 0; // reward_num:number = 0; @property(Node) coins_node:Node = null! @property(Node) lv_node:Node = null! @property(Node) chou_node:Node = null! @property(Node) time_node:Node = null! @property(Node) binfo_node:Node = null! FightTime:number = FightSet.FiIGHT_TIME /** 剩余复活次数 */ revive_times: number = 1; rewards:any[]=[] game_data:any={ exp:0, gold:0, diamond:0 } private lastTimeStr: string = ""; // 记录已触发的特殊刷怪索引 private spawnedSpecialIndices: Set = new Set(); onLoad(){ this.on(GameEvent.MissionStart,this.mission_start,this) this.on(GameEvent.MonDead,this.do_mon_dead,this) this.on(GameEvent.HeroDead,this.do_hero_dead,this) // this.on(GameEvent.FightEnd,this.fight_end,this) this.on(GameEvent.MissionEnd,this.mission_end,this) this.on(GameEvent.DO_AD_BACK,this.do_ad,this) this.on(GameEvent.CanUpdateLv,this.onLevelUp,this) this.on(GameEvent.ReviveSuccess, this.onReviveSuccess, this) } protected update(dt: number): void { if(!smc.mission.play) return if(smc.mission.pause) return if(smc.mission.in_fight){ if(smc.mission.stop_mon_action) return smc.vmdata.mission_data.fight_time+=dt this.FightTime-=dt // 检查特殊刷怪时间 this.checkSpecialSpawns(smc.vmdata.mission_data.fight_time); this.update_time(); } } update_time(){ let time = Math.max(0, this.FightTime); let m = Math.floor(time / 60); let s = Math.floor(time % 60); let str = `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`; if(str != this.lastTimeStr){ this.time_node.getChildByName("time").getComponent(Label).string = str; this.lastTimeStr = str; } } private checkSpecialSpawns(fightTime: number) { SpecialMonsterSchedule.forEach((item, index) => { if (!this.spawnedSpecialIndices.has(index) && fightTime >= item.time) { this.spawnedSpecialIndices.add(index); mLogger.log(this.debugMode, 'MissionComp', ` 触发特殊刷怪: ${item.desc}`); oops.message.dispatchEvent("SpawnSpecialMonster", { uuid: item.uuid, type: item.type, level: item.level }); } }); } // 升级奖励触发 onLevelUp(event: string, args: any) { mLogger.log(this.debugMode, 'MissionComp', ` 英雄升级到 ${args.lv} 级!`); // 默认每级都触发属性选择 // oops.message.dispatchEvent(GameEvent.AttrSelect); this.call_cards(args.lv) } call_cards(lv:number){ const rewardType = getLevelRewardType(lv); if(!rewardType || rewardType== null) return mLogger.log(this.debugMode, 'MissionComp', ` 触发奖励选择, 类型: ${rewardType}`); // 根据类型发送对应的事件 switch (rewardType) { case CardType.Talent: oops.message.dispatchEvent(GameEvent.TalentSelect); break; case CardType.Skill: oops.message.dispatchEvent(GameEvent.HeroSkillSelect); break; case CardType.Partner: oops.message.dispatchEvent(GameEvent.ToCallFriend); break; case CardType.Potion: oops.message.dispatchEvent(GameEvent.ShopOpen); break; case CardType.Attr: oops.message.dispatchEvent(GameEvent.AttrSelect); break; } } showLevelUpReward() { // TODO: 显示三选一技能/属性奖励界面 mLogger.log(this.debugMode, 'MissionComp', " 显示升级奖励界面 (TODO)"); } //奖励发放 do_reward(){ // 奖励发放 } do_mon_dead(event:any,data:any){ // mLogger.log(this.debugMode, 'MissionComp', " do_mon_dead",event,data) smc.vmdata.mission_data.mon_num-- // 计算并增加经验 // data 应该是怪物组件或包含怪物信息的对象 if (data && data.uuid) { // 默认值处理 const level = data.lv || 1; // 类型推断 let type = MonType.NORMAL; if (data.is_boss) { type = MonType.BOSS; } else if (data.is_elite) { type = MonType.ELITE; } else { // 兜底策略:根据Cost判断是否为精英怪 const cost = MonsterCost[data.uuid] || 1; if (cost >= 10) { type = MonType.ELITE; } } // 计算经验 let exp = calculateMonsterExp(data.uuid, level); smc.addExp(exp*5); this.cal_gold_reward(data, type); } } cal_gold_reward(data: any, type: MonType) { const cost = MonsterCost[data.uuid] || 1; const level = data.lv || 1; let add_gold = calculateMonsterGold(data.uuid, level, type); smc.updateGold(add_gold, false); } do_hero_dead(event:any,data:any){ // 收到 HeroDead 说明已经没有复活次数了,打开失败界面,等待玩家选择(复活或结束) // oops.message.dispatchEvent(GameEvent.FightEnd,{victory:false}) // 暂时不分发结束事件 this.open_Victory(null,true) } do_ad(){ if(this.ad_back()){ oops.message.dispatchEvent(GameEvent.AD_BACK_TRUE) smc.vmdata.mission_data.refresh_count+=FightSet.MORE_RC }else{ oops.message.dispatchEvent(GameEvent.AD_BACK_FALSE) } } ad_back(){ return true } async mission_start(){ // 防止上一局的 fight_end 延迟回调干扰新局 this.unscheduleAllCallbacks(); // 确保清理上一局的残留实体 this.cleanComponents(); oops.message.dispatchEvent(GameEvent.FightReady) this.node.active=true this.data_init() let loading=this.node.parent.getChildByName("loading") loading.active=true this.scheduleOnce(()=>{ loading.active=false },0.5) this.scheduleOnce(()=>{ this.to_fight() },0.1) } to_fight(){ smc.mission.in_fight=true oops.message.dispatchEvent(GameEvent.FightStart) //GameSetMonComp 监听刷怪 } open_Victory(e:any,is_hero_dead: boolean = false){ // 暂停游戏循环和怪物行为 // smc.mission.play = false; smc.mission.pause = true; // oops.message.dispatchEvent(GameEvent.FightEnd,{victory:false}) 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 }) } /** 复活成功回调,扣除次数 */ onReviveSuccess() { if (this.revive_times > 0) { this.revive_times--; mLogger.log(this.debugMode, 'MissionComp', ` 玩家复活,剩余次数: ${this.revive_times}`); } } fight_end(){ // mLogger.log(this.debugMode, 'MissionComp', "任务结束") // 延迟0.5秒后执行任务结束逻辑 this.scheduleOnce(() => { smc.mission.play=false this.cleanComponents() }, 0.5) } mission_end(){ // mLogger.log(this.debugMode, 'MissionComp', " mission_end") // 合并 FightEnd 逻辑:清理组件、停止游戏循环 smc.mission.play=false this.cleanComponents() this.node.active=false } data_init(){ // 重置金币为初始值 (如果需要保留金币,请注释掉此行) smc.vmdata.gold = 0; //局内数据初始化 smc 数据初始化 smc.mission.play = true; smc.mission.pause = false; smc.mission.stop_mon_action = false; smc.vmdata.mission_data.in_fight=false smc.vmdata.mission_data.fight_time=0 smc.vmdata.mission_data.level=0 this.FightTime=FightSet.FiIGHT_TIME this.rewards=[] // 改为数组,用于存储掉落物品列表 this.revive_times = 1; // 每次任务开始重置复活次数 this.spawnedSpecialIndices.clear(); // 重置特殊刷怪记录 // 重置全局属性加成和主角引用 (确保新一局数据干净) // smc.role = null; // 重置英雄数据,确保新一局是初始状态 smc.vmdata.hero = { name:'', path:'', as:0, type:0, lv:1, exp:0, exp_max: getLevelExp(1), exp_pre:0, hp:50, hp_max:100, mp:50, mp_max:100, def:0, ap:0, dis:0, crt:0, speed:0, skills:[], buff:[], tal:[], info:'', }; // mLogger.log(this.debugMode, 'MissionComp', "局内数据初始化",smc.vmdata.mission_data) } private cleanComponents() { // 优化销毁顺序:直接销毁实体,让ECS系统自动处理组件清理 // 这样可以避免在组件reset方法中访问已经被销毁的实体引用 ecs.query(ecs.allOf(HeroViewComp)).forEach(entity => { entity.destroy(); }); ecs.query(ecs.allOf(SkillView)).forEach(entity => { entity.destroy(); }); } /** 视图层逻辑代码分离演示 */ /** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */ reset() { this.node.destroy(); } }