当图形未铺满 整个rect时,实现精确点击
一. 原理
通过点击点向右或向左的射线与图形边框的交点数来判断是否处于图形内,奇数表示处于图形内,偶数表示图形外。

对于镂空图形同样适用

二. 代码实现
重载写IsRaycastLocationValid返回点击位置是否有效
List<Vector3> vertexList = new List<Vector3>();
vertexList 中存放的是图形边框顶点位置

public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
{
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform,screenPoint,eventCamera,out localPoint);
return IsValid(localPoint,vertexList);
}
//根据交点奇偶数判断
private bool IsValid(Vector2 localPoint, List<Vector3> vertexList)
{
Debug.Log("click ="+ (GetCrossPointNum(localPoint, vertexList) % 2 == 1));
return GetCrossPointNum(localPoint, vertexList) % 2 == 1;
}
//获取与边的交点数目
private int GetCrossPointNum(Vector2 localPoint, List<Vector3> vertexList)
{
Vector3 vert1 = Vector3.zero;
Vector3 vert2 = Vector3.zero;
int vertexCount = vertexList.Count;
int crossCount = 0;
for (int i = 0; i < vertexCount-1; i++)
{
Debug.Log("i=" + i);
vert1 = vertexList[i];
vert2 = vertexList[i+1];
if (IsYInRange(localPoint, vert1, vert2) && IsXInRange(localPoint, vert1, vert2))
{
crossCount++;
}
}
return crossCount;
}
//判断点的y值是否在边的两点的y值之间,在则有交点,反之则没有
private bool IsYInRange(Vector2 localPoint, Vector3 vert1,Vector3 vert2)
{
float max = Mathf.Max(vert1.y, vert2.y);
float min = Mathf.Min(vert1.y, vert2.y);
return min <= localPoint.y && localPoint.y <= max;
}
//获取交点的x坐标,取在点击点右面(或左面)的边
private bool IsXInRange(Vector2 localPoint, Vector3 vert1, Vector3 vert2)
{
float k = (vert2.y - vert1.y) / (vert2.x - vert1.x);
float crossX = vert2.x - (vert2.y - localPoint.y) / k;
return crossX >= localPoint.x;
}
本文介绍了一种基于射线与图形边框交点数目的点击检测算法,通过判断点击点是否位于图形内部,适用于未铺满整个rect的图形及镂空图形。文章详细解释了算法原理,并提供了Unity代码实现。

1804

被折叠的 条评论
为什么被折叠?



