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

Unity自定义碰撞脚本:子弹弹跳后速度异常增加问题排查

问题根源分析与修复方案

核心问题1:位置更新未做时间缩放

你的循环中直接将velocity加到位置上,没有乘以Time.fixedDeltaTime:

bulletTransf.position += velocity; // 错误:速度单位是米/秒,未匹配帧时间

velocity的单位是米/秒,而FixedUpdate的执行间隔是Time.fixedDeltaTime(通常为0.02秒),直接叠加velocity会让实际移动速度变成设定值的1/Time.fixedDeltaTime倍(比如50倍),完全违背速度的物理意义。

同时重力的叠加是正确的(乘以了Time.fixedDeltaTime),这就导致速度增长和位置更新的缩放完全不匹配,碰撞反弹后错误的速度会被进一步放大,最终出现速度异常增加的现象。

核心问题2:碰撞法线方向错误

你计算碰撞法线的逻辑是:

var collisionNormal = ((Vector2)bulletTransf.position - collisionPoints[0]).normalized;

collisionPoints[0]是碰撞体表面到子弹的最近点,当子弹穿透碰撞体内部时,子弹位置 - 最近点的向量指向碰撞体内部,和实际需要的“碰撞体表面指向外部”的法线方向完全相反。错误的法线会让Vector2.Reflect计算出错误的反弹方向,比如子弹在碰撞体内部来回反弹,每次叠加重力后速度越来越大。

次要问题:重力施加的判断逻辑错误

if (velocity.y > -gravityIntensity)
    velocity += gravityIntensity * Time.fixedDeltaTime * Vector3.down;

用加速度值gravityIntensity作为终端速度的阈值完全不合理——终端速度是速度值(比如-10米/秒),而非加速度。这个判断会导致重力施加不完整,甚至在某些场景下错误叠加。


修复后的代码

var velocity = speed * transform.right;
var collDetect = bullet.GetComponent<CollisionDetect>();
var bulletTransf = bullet.transform;
bulletTransf.position = transform.position;

// 终端速度(根据需求调整,单位:米/秒)
float terminalVelocity = -10f;

collDetect.OnTriggerEnter += coll =>
{
    if (coll.gameObject.layer != environmentLayer) return;

    var collisionPoints = collDetect.Colliders
        .Where(c=>c.gameObject.layer == environmentLayer)
        .Select(c=>c.ClosestPoint(bulletTransf.position))
        .ToArray();

    // 修正法线方向:碰撞体表面指向外部(指向子弹)
    var collisionNormal = ((Vector2)collisionPoints[0] - bulletTransf.position).normalized;
    var bounceVector = Vector2.Reflect(velocity, collisionNormal);
    velocity = bounceVector;

    // 可选:添加微小偏移避免子弹卡在碰撞体内
    bulletTransf.position += collisionNormal * 0.01f;
};

collDetect.OnObjDisable += collDtct =>
{
    collDetect.MyCollider.isTrigger = true;

    collDtct.EmptyOnTriggerEnter();
    collDtct.EmptyOnTriggerExit();
    collDtct.EmptyOnObjDisable();
};

while (true)
{
    // 位置更新乘以Time.fixedDeltaTime,匹配速度单位
    bulletTransf.position += velocity * Time.fixedDeltaTime;

    // 修正重力逻辑:持续施加直到达到终端速度
    if (velocity.y > terminalVelocity)
        velocity += gravityIntensity * Time.fixedDeltaTime * Vector3.down;

    yield return fixedUpdate;
}

额外注意事项

  • 确保speed的单位是米/秒,和Unity物理系统单位统一;
  • 如果不需要终端速度,可直接移除if (velocity.y > terminalVelocity)判断,持续施加重力;
  • 碰撞后的微小位置偏移可避免子弹卡在碰撞体内部反复触发碰撞。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 04:45:00