[UnityUI]不规则图片的点击响应

本文介绍了如何通过重写Image组件的IsRaycastLocationValid函数并添加PolygonCollider2D组件来精确控制不规则图片的点击响应范围。通过计算多边形顶点在屏幕上的位置并实现多边形内点检测算法,解决了点击镂空区域仍触发响应的问题。测试中发现仍有轻微误差,计划进一步优化。

参考链接:http://www.xuanyusong.com/archives/3492


当点击一张不规则图片时,点击镂空区域时,还是会发生响应。



对于Image来说,判断是否点击有效的就是IsRaycastLocationValid函数了,因此要重写它。

另外要为不规则图片挂上PolygonCollider2D组件,圈出响应的范围。


using UnityEngine;
using System.Collections;
using UnityEngine.UI;

/// <summary>
/// Image实现了接口ICanvasRaycastFilter
/// 该接口有函数IsRaycastLocationValid,返回点击是否有效
/// </summary>
public class ImagePlus : Image {

	PolygonCollider2D collider;
    LineRenderer l;

	void Awake()
	{
	    collider = GetComponent<PolygonCollider2D>();
        l = GetComponent<LineRenderer>();
	}

	override public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
	{
        DrawLine();
		return ContainsPoint(collider.points,sp);
	}

    //多边形顶点,屏幕点击坐标
	bool ContainsPoint (Vector2[] polyPoints, Vector2 p) 
    { 
		int j = polyPoints.Length - 1; 
		bool inside = false; 

		for (int i = 0; i < polyPoints.Length; i++) 
        {
            polyPoints[i].x += transform.position.x;
            polyPoints[i].y += transform.position.y;
			if ( ((polyPoints[i].y < p.y && p.y <= polyPoints[j].y) || (polyPoints[j].y < p.y && p.y <= polyPoints[i].y)) &&
                  (polyPoints[i].x + (p.y - polyPoints[i].y) / (polyPoints[j].y - polyPoints[i].y) * (polyPoints[j].x - polyPoints[i].x)) > p.x) 
				inside = !inside;

            j = i;
		} 
		return inside; 
	}

    //画出多边形区域
    void DrawLine()
    {
        l.SetVertexCount(collider.points.Length);
        for (int i = 0; i < collider.points.Length; i++)
        {
            float x = collider.points[i].x + transform.position.x;
            float y = collider.points[i].y + transform.position.y;
            Vector3 a = new Vector3(x,y,0);
            l.SetPosition(i,a);
        }
    }
}

解释:

1.PolygonCollider2D.points得到的点,其坐标是相对于图片中心的,也就是说,无论图片怎么移动,PolygonCollider2D.points中的点的坐标都是不变的,因此,为了得到多边形顶点的屏幕坐标,要加上图片的中心坐标。

2.算法是判断点是否在多边形内,原理可以看这里。其中涉及到射线与线段是否相交,要用到直线方程的点斜式,根据交点个数,从而判断点是否在多边形内。


在测试中,发现响应范围还是有一些误差,在某些离边缘外较近的地方还是会有响应,调整了一些参数还是不能解决,这里先放一放了。


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

后来发现一个更简单的方法:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class TestTouch : MonoBehaviour {

    private Image image;
    private PolygonCollider2D polygonCollider2D;
    
	// Use this for initialization
	void Start () 
    {
        image = GetComponent<Image>();
        polygonCollider2D = GetComponent<PolygonCollider2D>();
	}
	
	// Update is called once per frame
	void Update () 
    {
        if(Input.GetMouseButtonDown(0))
            if (polygonCollider2D.OverlapPoint(Input.mousePosition))
                image.enabled = !image.IsActive();
	}
}


### 处理 Unity不规则形状图片Unity 中处理和使用不规则形状的图片可以通过多种方式实现,具体取决于项目的实际需求和技术栈的选择。 #### 方法一:调整 `alphaHitTestMinimumThreshold` 通过设置 `Image` 组件中的 `alphaHitTestMinimumThreshold` 属性,可以控制图像透明度阈值下的点击检测行为。当像素的 alpha 值低于设定的阈值时,该位置将不会触发点击事件[^1]。 ```csharp using UnityEngine; using UnityEngine.UI; public class MyImage : MonoBehaviour { private Image image; private void Start() { image = transform.GetComponent<Image>(); image.alphaHitTestMinimumThreshold = 0.1f; } } ``` 这种方法适用于简单的半透明效果,并且不需要额外的碰撞器配置。 #### 方法二:自定义 `IsRaycastLocationValid` 函数 为了更精确地处理复杂的不规则形状,可以在继承自 `UnityEngine.UI.Image` 的类中重写 `IsRaycastLocationValid` 函数,利用 `Collider2D` 来判断射线是否击中目标对象[^4]。 ```csharp using UnityEngine; using UnityEngine.UI; public class CustomImageButton : Image { public override bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera) { return GetComponent<Collider2D>().OverlapPoint(sp); } } ``` 此方案适合那些需要高度定制化交互逻辑的应用场景,特别是当涉及到复杂几何结构的时候。 #### 方法三:基于 RenderTexture 实现高级解决方案 对于更高阶的需求,还可以考虑采用渲染纹理(Render Texture)技术来捕捉屏幕上的特定区域并分析其颜色信息,从而决定是否响应用户的输入操作[^5]。 虽然这种方式提供了极大的灵活性,但也伴随着性能开销较大的问题,在选择前需权衡利弊。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值