之前使用的方法是:
bool PosInBounds(Transform trans,Bounds bounds) { return bounds.Contains(transform.position); }
一句話就搞定了,但是!
在開發防穿過程中發現使用BoxCollider的Bounds有問題:
當BoxCollider有旋轉角度的時候,Bounds會比實際的BoxCollider范圍大。
如下圖:
所以決定自己算一下邊界:
public Vector3[] GetBoxPoints(Collider collider) { Vector3[] allPoints = new Vector3[8]; Quaternion quaternion = collider.transform.rotation; BoxCollider boxCollider = null; try { boxCollider = (BoxCollider)collider; } catch { return new Vector3[0]; } Vector3 c = collider.bounds.center; Vector3 size = new Vector3(boxCollider.size.x * boxCollider.transform.lossyScale.x, boxCollider.size.y * boxCollider.transform.lossyScale.y, boxCollider.size.z * boxCollider.transform.lossyScale.z); float rx = size.x / 2f; float ry = size.y / 2f; float rz = size.z / 2f; allPoints[0] = c + quaternion * new Vector3(-rx, -ry, rz); allPoints[1] = c + quaternion * new Vector3(rx, -ry, rz); allPoints[2] = c + quaternion * new Vector3(rx, -ry, -rz); allPoints[3] = c + quaternion * new Vector3(-rx, -ry, -rz); allPoints[4] = c + quaternion * new Vector3(-rx, ry, rz); allPoints[5] = c + quaternion * new Vector3(rx, ry, rz); allPoints[6] = c + quaternion * new Vector3(rx, ry, -rz); allPoints[7] = c + quaternion * new Vector3(-rx, ry, -rz); return allPoints; }
要是想看到邊界可以在Scene場景繪制出來:
void DrawLine(Collider collider) { Vector3[] points = GetBoxPoints(collider); if (points.Length == 0) { return; } #region 底面 Debug.DrawLine(points[0], points[1], Color.red); Debug.DrawLine(points[1], points[2], Color.red); Debug.DrawLine(points[2], points[3], Color.red); Debug.DrawLine(points[0], points[3], Color.red); #endregion #region 頂面 Debug.DrawLine(points[4], points[5], Color.red); Debug.DrawLine(points[5], points[6], Color.red); Debug.DrawLine(points[6], points[7], Color.red); Debug.DrawLine(points[4], points[7], Color.red); #endregion Debug.DrawLine(points[0], points[4], Color.red); Debug.DrawLine(points[1], points[5], Color.red); Debug.DrawLine(points[2], points[6], Color.red); Debug.DrawLine(points[3], points[7], Color.red); }
畫出來后如圖:
黃色和綠色的線重疊后顯示了黃色。
這就為判斷邊界提供了依據。
獲取到八個頂點后計算圍成立方體的6個面:
public bool PosInBounds(Transform trans,Collider collider) { Vector3[] points = GetBoxPoints(collider); Plane forward = new Plane(points[0], points[1], points[2]); Plane back = new Plane(points[4], points[5], points[6]); Plane left = new Plane(points[3], points[2], points[6]); Plane right = new Plane(points[0], points[1], points[5]); Plane up = new Plane(points[3], points[0], points[4]); Plane down = new Plane(points[2], points[1], points[5]); bool isEnterForwardBack = forward.GetSide(trans.position) != back.GetSide(trans.position); bool isEnterLeftRight = left.GetSide(trans.position) != right.GetSide(trans.position); bool isEnterUpDown = up.GetSide(trans.position) != down.GetSide(trans.position); return isEnterForwardBack && isEnterLeftRight && isEnterUpDown; }
獲取6個面后,直接判斷:
點是不是在兩個相對的面中間,即可知道是不是在BoxCollider中。
實際應用中可以用來計算人物移動、攝像機移動防穿透。