fix(hero): 修复实体销毁时可能出现的空引用问题
优化MissionComp中实体销毁逻辑,改为直接销毁实体让ECS处理组件清理 在HeroViewComp中添加多处model空值检查,防止销毁过程中访问null引用 移除reset方法中不必要的状态重置,由ECS系统统一处理
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user