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

Unity 3D中投射物调用Destroy(gameObject)不生效问题排查

问题原因

你当前的碰撞检测和销毁逻辑失效,是三个核心问题导致的:

  • Physics.CheckSphere 调用时没有传入层过滤参数,默认会扫描所有层的碰撞体。如果投射物自身挂载了碰撞体,或者生成位置处于玩家角色、枪械模型的碰撞体范围内,投射物在实例化的第一帧就会触发判定直接销毁,根本无法正常飞行;如果投射物飞行速度较快,单帧移动距离超过检测半径+碰撞体厚度,会直接出现隧穿现象——一帧时间内穿过碰撞体,检测范围全程没有覆盖到碰撞对象,自然不会触发销毁逻辑。
  • 销毁逻辑的触发条件和伤害逻辑的触发条件不匹配:只要检测半径内存在任意碰撞体(包括墙壁、地面、掩体、非敌人单位),代码就会直接销毁投射物,但只有碰撞对象处于enemy层时才会触发伤害计算,和你预期的"碰撞即销毁、命中敌人才造成伤害"的逻辑完全不符。
  • 物理检测逻辑写在Update生命周期里本身就不符合Unity物理系统的运行规则。Update是每帧渲染前的回调,调用间隔受设备帧率影响波动极大,而物理系统是按固定时间步在FixedUpdate阶段更新,时序不同步会直接导致检测结果频繁出错。
修复方案

最稳妥的实现方式是抛弃手动每帧扫球体的逻辑,改用Unity原生物理碰撞回调,从根源上避免时序、层干扰的问题:

  1. 先完成基础配置调整
  • 给投射物挂载的Rigidbody组件关闭重力(如果你做的是直射枪弹类投射物),将Collision Detection模式设置为Continuous Dynamic,避免高速移动时出现隧穿。
  • 在Unity Layer设置中单独创建投射物专属层,在碰撞矩阵中关闭投射物层与玩家层、武器层的碰撞交互,避免投射物生成时就和自身/玩家模型产生碰撞。
  1. 替换原有Update逻辑,使用物理回调实现需求
    如果追求更流畅的高速投射物表现、不需要碰撞后的物理反弹效果,就把投射物碰撞体的Is Trigger选项勾选,使用触发回调实现逻辑:
// 保留你原有逻辑中伤害范围、发送者的赋值即可
public float[] damageAmount;
public GameObject sender;
public LayerMask enemyLayer;

// 删除原有Update方法,替换为以下触发回调
private void OnTriggerEnter(Collider other)
{
    // 判断碰撞对象是否为敌人层
    if ((enemyLayer.value & (1 << other.gameObject.layer)) != 0)
    {
        BasicAI target = other.GetComponent<BasicAI>();
        if (target != null)
        {
            int finalDamage = (int)Random.Range(damageAmount[0], damageAmount[1]);
            target.damage(finalDamage, sender.transform);
        }
    }
    // 无论碰撞到什么对象(墙体、地面、敌人)都销毁投射物
    Destroy(gameObject);
}

如果需要实体碰撞效果(比如火箭弹碰撞反弹的需求),就取消碰撞体的Is Trigger勾选,把回调换成OnCollisionEnter,层判断和伤害逻辑和上述代码一致即可。
3. 如果你一定要保留手动球体检测的实现(不推荐),至少要做以下修正:

  • 将检测逻辑移到FixedUpdate中执行,和物理系统更新时序对齐
  • 所有球体检测调用都传入层过滤参数,将检测中心沿投射物前进方向偏移半个身位,避免检测到投射物自身的碰撞体
  • 投射物的移动逻辑不要直接修改transform.position,改用Rigidbody.MovePosition,避免位置跳变导致检测失效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 09:12:16