You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用Destroy()后脚本仍执行?Unity碰撞回调问题咨询

Unity中Destroy与脚本启用/禁用的生效时机问题解答

核心结论

是的,Unity里调用Destroy()或设置脚本enabled=false都不会立即生效。

原因解释

  1. Destroy(gameObject)的执行逻辑:
    Unity不会在调用Destroy的瞬间销毁对象,而是将对象标记为待销毁状态加入销毁队列。要等到当前帧的所有Update、FixedUpdate、碰撞回调等所有同步逻辑执行完毕后,才会在帧的末尾阶段真正销毁对象。所以调用Destroy之后,当前方法的剩余代码会正常执行,甚至同一帧内如果有其他碰撞触发回调,脚本依然会响应——因为此时对象还没被真正移除。

  2. 脚本enabled=false的生效时机:
    脚本启用状态的变更同样不会立即中断当前正在执行的方法,要等当前帧的所有逻辑跑完后,才会在下一帧开始时生效。所以同一帧内的后续回调依然会触发,直到帧结束。

你的代码问题分析

你遇到的health=-1情况,本质是同一帧内有两次碰撞触发了OnCollisionEnter2D:

  • 第一次碰撞:health从1降到0,进入死亡分支,调用Destroy(gameObject),但对象此时还没被销毁。
  • 第二次碰撞:同一帧内触发,脚本仍能响应回调,health再次减1变成-1,进入死亡分支后打印数值,之后再次调用Destroy(但对象已经标记为待销毁,重复调用无影响)。
  • 不会出现-2是因为第二次处理完后,对象已标记待销毁,后续帧不会再触发相关逻辑。

解决方法

最可靠的方式是添加一个死亡状态标记,在回调开头就判断是否已死亡,直接终止逻辑:

private bool isDead; // 新增死亡标记

private void CheckDamageCollision(Collision2D other)
{
    if (isDead) return; // 已死亡直接返回,不再处理任何伤害
    if (!other.gameObject.CompareTag(Constants.TAG_ENEMY) && !other.gameObject.CompareTag(Constants.TAG_OBSTACLE) && !other.gameObject.CompareTag(Constants.TAG_ENEMY_WEAPON)) return;
    if (justDamage) return;
    
    --health;
    PlayerDamage?.Invoke(health);
    
    if (health < 1)
    {
        isDead = true; // 立即标记死亡
        print("Health : " + health);
        PlayerDead?.Invoke();
        IgnoreLayerMatrix(false);
        Destroy(gameObject);
        return;
    }
    StartCoroutine(WaitNextDamageCollide());
}

这个标记是立即生效的,能确保同一帧内的后续碰撞不会再执行伤害逻辑,彻底避免health被多次减少的问题。


内容的提问来源于stack exchange,提问作者Nyein Chan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 11:57:25