大修
This commit is contained in:
85
Assets/Scripts/SLSUtilities/General/ColliderExtensions.cs
Normal file
85
Assets/Scripts/SLSUtilities/General/ColliderExtensions.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace SLSUtilities.General
|
||||
{
|
||||
public static class ColliderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断一个世界坐标点是否在 BoxCollider 内部(支持旋转和缩放)
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断一个世界坐标点是否在 SphereCollider 内部
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断一个世界坐标点是否在 CapsuleCollider 内部
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通用入口:根据 Collider 类型自动选择检测方法
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user