Files
heros/assets/script/game/map/MissionComp.ts
panw 56f45a7bb4 fix(hero): 修复实体销毁时可能出现的空引用问题
优化MissionComp中实体销毁逻辑,改为直接销毁实体让ECS处理组件清理
在HeroViewComp中添加多处model空值检查,防止销毁过程中访问null引用
移除reset方法中不必要的状态重置,由ECS系统统一处理
2025-10-30 15:51:41 +08:00

159 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { _decorator, Vec3,Animation, instantiate, Prefab, Node } 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 { FightSet} from "../common/config/Mission";
import { GameEvent } from "../common/config/GameEvent";
import { HeroViewComp } from "../hero/HeroViewComp";
import { UIID } from "../common/config/GameUIConfig";
import { AtkConCom } from "../skill/AtkConCom";
import { SkillViewCom } from "../skill/SkillViewCom";
const { ccclass, property } = _decorator;
//@todo this is a test
/** 视图层对象 */
@ccclass('MissionComp')
@ecs.register('MissionComp', false)
export class MissionComp extends CCComp {
// VictoryComp:any = null;
// reward:number = 0;
// reward_num:number = 0;
rewards:any[]=[]
game_data:any={
exp:0,
gold:0,
diamond:0
}
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.show_uplv_button,this)
}
protected update(dt: number): void {
if(!smc.mission.play||smc.mission.pause){
return
}
if(smc.mission.in_fight){
smc.vmdata.mission_data.fight_time+=dt
}
}
//奖励发放
do_reward(){
// 奖励发放
}
do_drop(drop_item:any[],game_data:any={exp:0,gold:0,diamond:0}){
// console.log("[MissionComp] do_drop",drop_item,game_data)
}
do_mon_dead(event:any,data:any){
// console.log("[MissionComp] do_mon_dead",event,data)
smc.vmdata.mission_data.mon_num--
}
do_hero_dead(event:any,data:any){
// console.log("[MissionComp] do_hero_dead",event,data)
smc.vmdata.mission_data.hero_num--
if(smc.vmdata.mission_data.hero_num<=0) {
oops.message.dispatchEvent(GameEvent.FightEnd,{victory:false})
oops.gui.open(UIID.Victory,{victory:false,rewards:this.rewards,game_data:this.game_data})
}
}
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(){
// console.log("[MissionComp] ** 1 ** mission_start")
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) //MissionMonComp 监听刷怪
}
to_end_fight(){
oops.message.dispatchEvent(GameEvent.FightEnd,{victory:false})
oops.gui.open(UIID.Victory,{victory:false,rewards:this.rewards,game_data:this.game_data})
}
fight_end(){
// console.log("任务结束")
// 延迟0.5秒后执行任务结束逻辑
this.scheduleOnce(() => {
smc.mission.play=false
smc.mission.pause=false
this.cleanComponents()
}, 0.5)
}
mission_end(){
// console.log("[MissionComp] mission_end")
this.node.active=false
}
data_init(){
//局内数据初始化 smc 数据初始化
smc.mission.play = true;
smc.vmdata.mission_data.in_fight=false
smc.vmdata.mission_data.fight_time=0
smc.vmdata.mission_data.level=0
this.rewards=[] // 改为数组,用于存储掉落物品列表
// console.log("[MissionComp]局内数据初始化",smc.vmdata.mission_data)
}
private cleanComponents() {
// 优化销毁顺序直接销毁实体让ECS系统自动处理组件清理
// 这样可以避免在组件reset方法中访问已经被销毁的实体引用
ecs.query(ecs.allOf(HeroViewComp)).forEach(entity => {
entity.destroy();
});
ecs.query(ecs.allOf(AtkConCom)).forEach(entity => {
entity.destroy();
});
ecs.query(ecs.allOf(SkillViewCom)).forEach(entity => {
entity.destroy();
});
}
/** 视图层逻辑代码分离演示 */
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
reset() {
this.node.destroy();
}
}