From 56f45a7bb48c2bec48bc131e174d386fa419ee2d Mon Sep 17 00:00:00 2001 From: panw Date: Thu, 30 Oct 2025 15:51:41 +0800 Subject: [PATCH] =?UTF-8?q?fix(hero):=20=E4=BF=AE=E5=A4=8D=E5=AE=9E?= =?UTF-8?q?=E4=BD=93=E9=94=80=E6=AF=81=E6=97=B6=E5=8F=AF=E8=83=BD=E5=87=BA?= =?UTF-8?q?=E7=8E=B0=E7=9A=84=E7=A9=BA=E5=BC=95=E7=94=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化MissionComp中实体销毁逻辑,改为直接销毁实体让ECS处理组件清理 在HeroViewComp中添加多处model空值检查,防止销毁过程中访问null引用 移除reset方法中不必要的状态重置,由ECS系统统一处理 --- assets/script/game/hero/HeroViewComp.ts | 21 +++++++++++++++------ assets/script/game/map/MissionComp.ts | 14 +++++++++++--- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/assets/script/game/hero/HeroViewComp.ts b/assets/script/game/hero/HeroViewComp.ts index d0f1deb9..48636ff2 100644 --- a/assets/script/game/hero/HeroViewComp.ts +++ b/assets/script/game/hero/HeroViewComp.ts @@ -69,7 +69,7 @@ export class HeroViewComp extends CCComp { /** 方向 */ this.node.setScale(this.scale,1); this.top_node.setScale(this.scale,1); - if(this.model.is_boss){ + if(this.model && this.model.is_boss){ this.top_node.position=v3(this.node.position.x,this.node.position.y+100,0) } /* 显示角色血*/ @@ -94,6 +94,9 @@ export class HeroViewComp extends CCComp { update(dt: number){ if(!smc.mission.play || smc.mission.pause) return; + // 添加安全检查,防止在实体销毁过程中访问null的model + if (!this.model) return; + // ✅ View 层职责:处理表现相关的逻辑 this.processDamageQueue(); // 伤害数字显示队列 @@ -245,13 +248,15 @@ export class HeroViewComp extends CCComp { } add_shield(shield:number){ // 护盾数据更新由 Model 层处理,这里只负责视图表现 - if(this.model.shield>0) this.show_shield(this.model.shield, this.model.Attrs[Attrs.SHIELD_MAX]); + if(this.model && this.model.shield>0) this.show_shield(this.model.shield, this.model.Attrs[Attrs.SHIELD_MAX]); } health(hp: number = 0, is_num:boolean=true) { // 生命值更新由 Model 层处理,这里只负责视图表现 this.heathed(); - this.hp_show(hp, this.model.Attrs[Attrs.HP_MAX]); + if(this.model) { + this.hp_show(hp, this.model.Attrs[Attrs.HP_MAX]); + } } @@ -260,6 +265,9 @@ export class HeroViewComp extends CCComp { * 由 HeroAtkSystem 调用,只负责视觉效果和事件通知 */ do_dead(){ + // 添加安全检查 + if (!this.model) return; + // 防止重复触发 if(this.model.is_count_dead) return; this.model.is_count_dead = true; // 防止重复触发,必须存在防止重复调用 @@ -310,13 +318,13 @@ export class HeroViewComp extends CCComp { /** 死亡触发器(预留,用于天赋/特殊效果) */ do_dead_trigger(){ - if(this.model.is_dead || this.model.fac === FacSet.MON) return; + if(!this.model || this.model.is_dead || this.model.fac === FacSet.MON) return; // 预留:天赋触发、复活检查等 } /** 受击触发器(预留,用于天赋/特殊效果) */ do_atked_trigger(){ - if(this.model.is_dead || this.model.fac === FacSet.MON) return; + if(!this.model || this.model.is_dead || this.model.fac === FacSet.MON) return; // 预留:反击、护盾触发等 } @@ -335,7 +343,6 @@ export class HeroViewComp extends CCComp { } reset() { - this.model.is_dead = false; const collider = this.getComponent(Collider2D); if (collider) { collider.off(Contact2DType.BEGIN_CONTACT); @@ -387,6 +394,8 @@ export class HeroViewComp extends CCComp { /** 立即显示伤害效果 */ private showDamageImmediate(damage: number, isCrit: boolean, anm:string="atked") { + if (!this.model) return; + this.hp_show(this.model.hp, this.model.Attrs[Attrs.HP_MAX]); this.in_atked(anm, this.model.fac==FacSet.HERO?1:-1); if (isCrit) { diff --git a/assets/script/game/map/MissionComp.ts b/assets/script/game/map/MissionComp.ts index 17fa4c80..0949e46e 100644 --- a/assets/script/game/map/MissionComp.ts +++ b/assets/script/game/map/MissionComp.ts @@ -136,9 +136,17 @@ export class MissionComp extends CCComp { } private cleanComponents() { - ecs.query(ecs.allOf(HeroViewComp)).forEach(entity => {entity.remove(HeroViewComp);entity.destroy()}); - ecs.query(ecs.allOf(AtkConCom)).forEach(entity => {entity.remove(AtkConCom);entity.destroy()}); - ecs.query(ecs.allOf(SkillViewCom)).forEach(entity => {entity.remove(SkillViewCom);entity.destroy()}); + // 优化销毁顺序:直接销毁实体,让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(); + }); }