之前使用的方法是:
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中。
实际应用中可以用来计算人物移动、摄像机移动防穿透。