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 文档
备注:内容仅供参考。
