PAYATHON 2026

CircleCast 初始重叠时 RaycastHit2D.fraction 如何计算?

数据小许

当起始圆形已与 Collider2D 重叠,且查询将该重叠报告为命中时,RaycastHit2D.fraction 应为 0。即使圆心位于 Collider2D 外部也是如此,因为 CircleCast 检测的是整个圆形覆盖的区域。

fraction 表示投射走了多远

显式传入有限且大于 0 的最大投射距离 maxDistance 时,可以这样理解:

hit.fraction = hit.distance / maxDistance

hit.distance 表示圆形从起始位置移动到命中位置所经过的距离。如果起始位置已经重叠,圆形无须移动即可命中,因此距离和比例均为 0。这一结论基于查询距离的定义,并非运行测试结果。Unity fraction 文档

为什么不能用圆心到 hit.point 的距离

需要区分两个位置:

  • hit.point:查询返回的接触点。
  • hit.centroid:命中时投射圆形的中心位置。

对于 CircleCast,hit.distance 对应起始圆心到命中时圆心位置的移动距离。圆心到 hit.point 的距离描述的是另一种几何关系,不能用于计算投射进度。Unity 的 distance 文档说明,形状查询根据 centroid 所表示的位置计算距离,简单的 raycast 或 linecast 则使用 point。Unity distance 文档

例如,圆形需要移动 2 个世界单位才接触目标,最大投射距离为 10,则 fraction = 0.2。如果圆形一开始就与目标重叠,移动距离为 0,fraction = 0。这两种情况都无须计算圆心到接触点的距离。

如何在项目中检查

先设置有限且大于 0 的 maxDistance,确认查询命中 Collider2D 后,再查看返回的字段。下面的方法可以放在已有的 MonoBehaviour 类中:

void InspectCircleCast(
    Vector2 origin,
    float radius,
    Vector2 direction,
    float maxDistance,
    LayerMask layerMask)
{
    RaycastHit2D hit = Physics2D.CircleCast(
        origin, radius, direction, maxDistance, layerMask);

    if (hit.collider == null)
    {
        Debug.Log("No hit");
        return;
    }

    Debug.Log(
        $"collider={hit.collider.name}, " +
        $"distance={hit.distance}, fraction={hit.fraction}, " +
        $"point={hit.point}, centroid={hit.centroid}");
}

将 origin 放在目标 Collider2D 外部,增大 radius,直到起始圆形与目标实际重叠,即可检查题述场景。示例用于观察项目行为,未预设或声称某个 Unity 版本的实测输出。

使用时注意什么

先判断 hit.collider != null,再读取和解释命中数据。不能仅凭 fraction == 0 判断发生了命中,也不能仅凭零距离命中断定存在穿透,因为起始位置恰好接触时,移动距离也可能为 0。

如果业务需要明确判断起始区域是否重叠,可以另做 Physics2D.OverlapCircle 查询,并保持相关筛选条件一致。

上述比例公式只适用于有限且大于 0 的最大投射距离。使用默认无限距离时,不要直接套用该公式。Unity 的 fraction 文档对无限距离查询另有说明:此时 fraction 与返回的 distance 相同,不保证处于 [0, 1] 范围。Unity fraction 文档

备注:内容仅供参考。