效果如下
有两种比较主流的实现方式,一种是根据图片像素的alpha值来判断是否触发响应,还有一种是自己框选一个多边体,判断点击位置是否在多变体内。
第一种像素使用限制颇多,但是也有一定的使用场景,https://www.cnblogs.com/msxh/p/9283266.html,这里马三详细说了使用方法和限制
我在这里实现的是第二种计算的方式
P点是鼠标位置,ABCD是多边形的点,如果图上对每个点计算叉乘的方向都是一致,那我们可以得出P点在多边形内部,有一定的叉乘知识应该可以推出来。叉乘可以看看这篇文章 https://blog.youkuaiyun.com/qq_33413868/article/details/87929981
下面上代码实现:
public class MImage : Image
{
//多边形使用PolygonCollider2D来代替,但是推荐自己写一个,我们只需要使用collider2D.points来按顺序获取所有
//的点,PolygonCollider2D似乎有些大材小用,这里只做演示
private PolygonCollider2D collider2D;
private bool? dir;
protected override void Awake()
{
base.Awake();
collider2D = GetComponent<PolygonCollider2D>();
}
/// <summary>
/// unity判断是否选中的方法,可以继承Image来重写
/// </summary>
/// <param name="screenPoint"></param>
/// <param name="eventCamera"></param>
/// <returns></returns>
public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
{
dir = null;
screenPoint = screenPoint - (Vector2)rectTransform.position;
int len = collider2D.points.Length;
for (int i = 0; i < len; i++)
{
//求每条边的方向向量
var side_dir = collider2D.points[(i + 1) % len] - collider2D.points[i];
//求当前点和边的向量叉乘 的朝向
bool _dir = Vector3.Cross(screenPoint - collider2D.points[i], side_dir).z > 0;
if (!dir.HasValue)
dir = _dir;
if (dir.Value != _dir)
return false;
}
return true;
}
}
还有第二种计算是使用collider自带的api
public bool IsRaycastLocationValid(Vector2 screenPos, Camera eventCamera)
{
var worldPoint = Vector3.zero;
var isInside = RectTransformUtility.ScreenPointToWorldPointInRectangle(
_rectTransform,
screenPos,
eventCamera,
out worldPoint
);
if (isInside)
{
isInside = _collider.OverlapPoint(worldPoint);
}
return isInside;
}