using UnityEngine; namespace SLSUtilities.General { public static class ColliderExtensions { /// /// 判断一个世界坐标点是否在 BoxCollider 内部(支持旋转和缩放) /// public static bool IsPointInside(this BoxCollider box, Vector3 worldPoint) { // 1. 将世界坐标转为该 Collider 的本地坐标(处理了旋转和位置) Vector3 localPoint = box.transform.InverseTransformPoint(worldPoint); // 2. 减去中心偏移 localPoint -= box.center; // 3. 计算实际的半长宽高(考虑 LossyScale 缩放) // 注意:BoxCollider 的 size 已经包含了本地缩放,InverseTransformPoint 已经处理了缩放的影响 Vector3 halfSize = box.size * 0.5f; // 4. AABB 判定 return Mathf.Abs(localPoint.x) <= halfSize.x && Mathf.Abs(localPoint.y) <= halfSize.y && Mathf.Abs(localPoint.z) <= halfSize.z; } /// /// 判断一个世界坐标点是否在 SphereCollider 内部 /// public static bool IsPointInside(this SphereCollider sphere, Vector3 worldPoint) { // 考虑中心偏移的世界坐标中心点 Vector3 center = sphere.transform.TransformPoint(sphere.center); // 计算缩放后的实际半径(Unity 以三个轴中缩放最大的为准) Vector3 lossyScale = sphere.transform.lossyScale; float maxScale = Mathf.Max(lossyScale.x, Mathf.Max(lossyScale.y, lossyScale.z)); float scaledRadius = sphere.radius * maxScale; // 距离平方判定,性能最高 float sqrDistance = (worldPoint - center).sqrMagnitude; return sqrDistance <= (scaledRadius * scaledRadius); } /// /// 判断一个世界坐标点是否在 CapsuleCollider 内部 /// public static bool IsPointInside(this CapsuleCollider capsule, Vector3 worldPoint) { // 转为本地坐标 Vector3 localPoint = capsule.transform.InverseTransformPoint(worldPoint); localPoint -= capsule.center; // 计算胶囊体内部中心轴线的半高度(不含两头的半圆) float radius = capsule.radius; float halfHeight = Mathf.Max(0f, (capsule.height * 0.5f) - radius); // 根据方向计算点到中心线段的最短距离 // direction: 0 = X, 1 = Y, 2 = Z Vector3 closestPointOnAxis = Vector3.zero; switch (capsule.direction) { case 0: closestPointOnAxis.x = Mathf.Clamp(localPoint.x, -halfHeight, halfHeight); break; case 1: closestPointOnAxis.y = Mathf.Clamp(localPoint.y, -halfHeight, halfHeight); break; case 2: closestPointOnAxis.z = Mathf.Clamp(localPoint.z, -halfHeight, halfHeight); break; } return (localPoint - closestPointOnAxis).sqrMagnitude <= (radius * radius); } /// /// 通用入口:根据 Collider 类型自动选择检测方法 /// public static bool IsPointInside(this Collider collider, Vector3 worldPoint) { if (collider is BoxCollider box) return box.IsPointInside(worldPoint); if (collider is SphereCollider sphere) return sphere.IsPointInside(worldPoint); if (collider is CapsuleCollider capsule) return capsule.IsPointInside(worldPoint); // 如果是 MeshCollider 等复杂形状,回退到 Bounds 粗略检测 return collider.bounds.Contains(worldPoint); } } }