
最近無意中拓展出這個東西,基于之前寫的2D多邊形檢測:
http://www.cnblogs.com/hont/p/6105997.html
而判斷兩條線相交的方法替換成了我後來寫的差乘判斷:
http://www.cnblogs.com/hont/p/6106043.html
應用還是比較廣泛的,特别是多邊形選區和地形處理上
代碼實作:
using UnityEngine;
public class Test : MonoBehaviour
{
public Transform testComparePoint;
public Transform[] pointsArray;
public float height = 4;
public bool IsInRange(Vector3 comparePoint)
{
var localComparePoint = transform.worldToLocalMatrix.MultiplyPoint3x4(comparePoint);
var flag = true;
flag &= localComparePoint.y <= height;
flag &= localComparePoint.y >= -height;
flag &= IsConcaveContain2D(pointsArray, localComparePoint);
if (flag)
return true;
return false;
}
public bool IsConcaveContain2D(Transform[] points, Vector3 compare)
{
const float VIRTUAL_RAYCAST_LEN = 100000;
var comparePoint = (points[1].localPosition + points[0].localPosition) * 0.5f;
var originPoint = compare;
comparePoint += (comparePoint - originPoint).normalized * VIRTUAL_RAYCAST_LEN;
int count = 0;
for (int i = 0; i < points.Length; i++)
{
var a = points[i % points.Length];
var b = points[(i + 1) % points.Length];
var r = IsLineSegmentIntersection(a.localPosition, b.localPosition, originPoint, comparePoint);
if (r) count++;
}
return count % 2 == 1;
}
public bool IsLineSegmentIntersection(Vector3 a, Vector3 b, Vector3 c, Vector3 d)
{
var crossA = Mathf.Sign(Vector3.Cross(d - c, a - c).y);
var crossB = Mathf.Sign(Vector3.Cross(d - c, b - c).y);
if (Mathf.Approximately(crossA, crossB)) return false;
var crossC = Mathf.Sign(Vector3.Cross(b - a, c - a).y);
var crossD = Mathf.Sign(Vector3.Cross(b - a, d - a).y);
if (Mathf.Approximately(crossC, crossD)) return false;
return true;
}
void OnDrawGizmos()
{
if (pointsArray == null) return;
if (testComparePoint != null)
{
var comparePoint = testComparePoint.transform.position;
if (IsInRange(comparePoint))
{
Gizmos.color = Color.red;
}
}
var cacheMatrix = Gizmos.matrix;
Gizmos.matrix = transform.localToWorldMatrix;
for (int i = 0; i < pointsArray.Length; i++)
{
var a = pointsArray[i];
var b = pointsArray[(i + 1) % pointsArray.Length];
if (a == null) continue;
if (b == null) continue;
var minA = a.localPosition;
var minB = b.localPosition;
var maxA = a.localPosition;
var maxB = b.localPosition;
minA.y = -height;
minB.y = -height;
maxA.y = height;
maxB.y = height;
Gizmos.DrawLine(minA, minB);
Gizmos.DrawLine(maxA, maxB);
Gizmos.DrawLine(minA, maxA);
Gizmos.DrawLine(minB, maxB);
}
Gizmos.color = Color.clear;
Gizmos.matrix = cacheMatrix;
}
}