?? 博客主頁:https://xiaoy.blog.csdn.net
?? 本文由 呆呆敲代碼的小Y 原創(chuàng),首發(fā)于 CSDN??
?? 學(xué)習(xí)專欄推薦:Unity系統(tǒng)學(xué)習(xí)專欄
?? 游戲制作專欄推薦:游戲制作
??Unity實(shí)戰(zhàn)100例專欄推薦:Unity 實(shí)戰(zhàn)100例 教程
?? 歡迎點(diǎn)贊 ?? 收藏 ?留言 ?? 如有錯(cuò)誤敬請指正!
?? 未來很長,值得我們?nèi)Ρ几案篮玫纳?
------------------??分割線??-------------------------
Unity零基礎(chǔ)到進(jìn)階 | Unity中 屏蔽指定UI點(diǎn)擊事件 的多種方法整理
在Unity中 屏蔽UI點(diǎn)擊事件的方法有很多種,本文來介紹幾種比較實(shí)用的方法,一起來看下吧。
一些基礎(chǔ)的方法這里簡單提一下,例如將Button組件的 Interactable
屬性設(shè)置為false,可以直接禁用按鈕的交互功能。這種方法簡單直接,適用于臨時(shí)禁用或條件性禁用UI元素的情況。
還有通過修改UI元素的isEnabled
屬性或監(jiān)聽并處理onClick事件,我們可以在運(yùn)行時(shí)根據(jù)游戲邏輯或用戶行為來決定是否屏蔽點(diǎn)擊事件。這種方法適用于需要復(fù)雜邏輯控制或動(dòng)態(tài)響應(yīng)的場景。
Unity中我們有時(shí)候會(huì)遇到一些帶有透明度或者形狀千奇百怪的圖片按鈕,有些時(shí)候可能并不希望點(diǎn)擊按鈕的透明區(qū)域時(shí)也觸發(fā)點(diǎn)擊事件,這個(gè)時(shí)候就要進(jìn)行額外處理,下面整理了幾種方法可以進(jìn)行參考使用!
一、Unity中 屏蔽透明區(qū)域的點(diǎn)擊事件
像素檢測 過濾透明區(qū)域
這種方法是通過讀取Sprite在某一點(diǎn)的像素值(RGBA),如果該點(diǎn)的像素值中的Alpha小于一定的閾值(比如0.5)則表示該點(diǎn)是透明的,即用戶點(diǎn)擊的位置在精靈邊界以外,否則用戶點(diǎn)擊的位置在精靈邊界內(nèi)部。
這種做法就是通過判斷點(diǎn)擊的某一點(diǎn)是否達(dá)到我們期望的像素Alpha閾值,達(dá)到閾值就響應(yīng)事件,未達(dá)到閾值就說明點(diǎn)擊了透明區(qū)域,此時(shí)不響應(yīng)事件。
UGUI在處理控件是否被點(diǎn)擊的時(shí)候,主要是根據(jù)IsRaycastLocationValid這個(gè)方法的返回值來進(jìn)行判斷的,而這個(gè)方法用到的基本原理則是判斷指定點(diǎn)對應(yīng)像素的RGBA數(shù)值中的Alpha是否大于某個(gè)指定臨界值。
1.1 使用Image組件自帶的參數(shù)檢測
而UGUI中可以通過Image組件拿到一個(gè)alphaHitTestMinimumThreshold
,這個(gè)值代表的含義就是期望的像素Alpha閾值,通過改變這個(gè)值就可以實(shí)現(xiàn)過濾透明區(qū)域的點(diǎn)擊事件。
this.GetComponent<Image>().alphaHitTestMinimumThreshold = 0.1f;
所以使用方法很簡單,拿到指定按鈕上的Image組件,改變這個(gè)Image的alphaHitTestMinimumThreshold即可實(shí)現(xiàn)過濾透明區(qū)域的所有點(diǎn)擊事件,下面看下實(shí)際使用方法及效果。
通過控制alpahThreshold
的值可以實(shí)現(xiàn)透明過濾的強(qiáng)度,也就是透明度過濾的閾值。比如alpahThreshold 為0則代表只過濾全透明的區(qū)域,alpahThreshold 為0.5則是把半透明一下的過濾掉,alpahThreshold 為1的話那就整張圖都被過濾了,都不會(huì)響應(yīng)事件。
準(zhǔn)備兩個(gè)帶有透明度的切圖,然后放置到場景的Button組件上,測試代碼如下:
using UnityEngine;
using UnityEngine.UI;
public class UnityImageAlphaTest : MonoBehaviour
{
public Button btnImage1;
public Button btnImage2;
[Header("透明度過濾閾值")]
public float alpahThreshold = 0.5f;
void Start()
{
btnImage1.onClick.AddListener(OnClickImage);
btnImage2.onClick.AddListener(OnClickImage);
btnImage2.GetComponent<Image>().alphaHitTestMinimumThreshold = alpahThreshold;
}
private void OnClickImage()
{
Debug.Log("點(diǎn)擊圖片測試!");
}
}
值得注意的是還需要把過濾透明區(qū)域的圖片設(shè)置為可讀寫狀態(tài)(Read/Write Enable 設(shè)置為true),如下圖所示,否則這種方法不會(huì)生效且會(huì)報(bào)錯(cuò)。
將兩個(gè)Button掛載到腳本中,第一個(gè)Button不參與透明過濾,第二個(gè)Button過濾透明區(qū)域點(diǎn)擊事件。
此時(shí)運(yùn)行Unity就可以看到效果了,效果如下:
1.2 根據(jù)點(diǎn)擊的坐標(biāo)計(jì)算該點(diǎn)的像素值是否滿足閾值
與上述直接使用Image組件的方法有所區(qū)別,這種方法是通過計(jì)算我們點(diǎn)擊的坐標(biāo)點(diǎn)的像素值是否達(dá)到閾值來判斷需要過濾。
但原理是相同的,都是通過像素檢測去判斷是否選擇過濾,下面看下實(shí)現(xiàn)代碼:
using UnityEngine;
using UnityEngine.UI;
public class Model_ButtonSetting : MonoBehaviour, ICanvasRaycastFilter
{
[Header("透明度過濾閾值")]
public float alpahThreshold = 0.1f;
protected Image _image;
void Start()
{
_image = GetComponent<Image>();
}
public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
{
//將選中的點(diǎn)轉(zhuǎn)換為Image區(qū)域內(nèi)的本地點(diǎn)
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(_image.rectTransform, sp, eventCamera, out localPoint);
Vector2 pivot = _image.rectTransform.pivot;
Vector2 normalizedLocal = new Vector2(pivot.x + localPoint.x / _image.rectTransform.rect.width, pivot.y + localPoint.y / _image.rectTransform.rect.height);
Vector2 uv = new Vector2(
_image.sprite.rect.x + normalizedLocal.x * _image.sprite.rect.width,
_image.sprite.rect.y + normalizedLocal.y * _image.sprite.rect.height);
uv.x /= _image.sprite.texture.width;
uv.y /= _image.sprite.texture.height;
//獲取指定紋理坐標(biāo)(u, v)處的像素顏色。它返回一個(gè)Color結(jié)構(gòu),其中包含紅、綠、藍(lán)和alpha通道的值。
//Color c = _image.sprite.texture.GetPixel((int)uv.x, (int)uv.y);
//用于在紋理上執(zhí)行雙線性插值以獲取像素顏色值,這個(gè)方法使用雙線性插值算法來估算紋理中某個(gè)位置的顏色,而不是直接從紋理的像素中讀取顏色。
Color c = _image.sprite.texture.GetPixelBilinear(uv.x, uv.y);
return c.a > alpahThreshold;
}
}
這種方法也需要把過濾透明區(qū)域的圖片設(shè)置為可讀寫狀態(tài)(Read/Write Enable 設(shè)置為true),否則這種方法也不會(huì)生效且會(huì)報(bào)錯(cuò)。
將上述腳本掛載到需要屏蔽透明區(qū)域的按鈕上即可生效,簡單易用。
二、Unity中屏蔽 不規(guī)則圖片按鈕點(diǎn)擊的事件
除了上述方法通過檢測圖片的透明區(qū)域來屏蔽點(diǎn)擊事件之外,還可以使用 PolygonCollider2D
多邊形碰撞組件 來實(shí)現(xiàn)不規(guī)則圖片的事件屏蔽方法,也是簡單易用,下面一起看下:
具體事例:
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(PolygonCollider2D))]
public class PolygonImageClick : MonoBehaviour, ICanvasRaycastFilter
{
/// <summary>
/// 2D多邊形碰撞器
/// </summary>
protected PolygonCollider2D m_polygonCollider2D;
protected Image _image;
void Start()
{
_image = GetComponent<Image>();
m_polygonCollider2D = GetComponent<PolygonCollider2D>();
}
public bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
{
Vector3 worldPos;
//將屏幕上的點(diǎn)轉(zhuǎn)換為世界坐標(biāo)中的點(diǎn),考慮到了矩形(RectTransform)的本地坐標(biāo)系
RectTransformUtility.ScreenPointToWorldPointInRectangle(_image.rectTransform, screenPoint, eventCamera, out worldPos);
return m_polygonCollider2D.OverlapPoint(worldPos);
}
}
通過繼承一個(gè)ICanvasRaycastFilter接口,實(shí)現(xiàn) IsRaycastLocationValid() 方法,在方法中判斷某點(diǎn)是否在多邊形碰撞器區(qū)域內(nèi)即可實(shí)現(xiàn)不規(guī)則區(qū)域的點(diǎn)擊。
將上述代碼掛載到有Image的組件上,然后調(diào)整多邊形不規(guī)則形狀用來適配我們的不規(guī)則圖片。
調(diào)整好多邊形后運(yùn)行游戲,即可實(shí)現(xiàn)只在多邊形區(qū)域內(nèi)可以實(shí)現(xiàn)點(diǎn)擊事件,其他區(qū)域就被過濾掉了。
效果如下:
這種方法不止可以過濾掉透明區(qū)域,還可以讓我們隨意指定范圍,并且不需要將圖片設(shè)置為可讀寫狀態(tài)(Read/Write Enable 開啟后加載時(shí)會(huì)多一份內(nèi)存消耗),內(nèi)存也不會(huì)白白多浪費(fèi),比起前面幾種方法有更高的擴(kuò)展性。
總結(jié)
-
在Unity游戲開發(fā)過程中,UI(用戶界面)的設(shè)計(jì)和管理是至關(guān)重要的一環(huán)。有時(shí),開發(fā)者可能希望屏蔽或禁用某些UI元素的點(diǎn)擊事件,以避免不必要的交互或錯(cuò)誤操作。文章來源:http://www.zghlxwxcb.cn/news/detail-837415.html
-
Unity中屏蔽指定UI點(diǎn)擊事件的方法多種多樣,從簡單的屬性設(shè)置到復(fù)雜的腳本編程和高級技術(shù)應(yīng)用,每種方法都有其適用的場景和優(yōu)缺點(diǎn)。開發(fā)者可以根據(jù)具體需求選擇合適的方法來實(shí)現(xiàn)UI點(diǎn)擊事件的屏蔽,從而提升游戲的用戶體驗(yàn)和穩(wěn)定性。文章來源地址http://www.zghlxwxcb.cn/news/detail-837415.html
到了這里,關(guān)于Unity零基礎(chǔ)到進(jìn)階 | Unity中 屏蔽指定UI點(diǎn)擊事件 的多種方法整理的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!