天天看點

Unity3D之事件的穿透和傳遞

一 , Scene設計

      Ⅰ, A和B是兄弟

      Ⅱ, C是A的孩子

Unity3D之事件的穿透和傳遞

二, 測試一(穿透測試)

 Ⅰ, 代碼

A , B , C 分别挂載A.cs , B.cs , C.cs , 分别如下

A.cs 代碼如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class A : MonoBehaviour, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("A click");
    }
}           

B.cs 代碼如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class B : MonoBehaviour, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("B click");
    }
}           

C.cs 代碼如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class C : MonoBehaviour, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("C click");
    }
}
           

Ⅱ, 測試

      A, 解除安裝 B 和 C的腳本 B.cs 和 C.cs

          1, 點選C的時候A會觸發事件

          2, 點選B的時候A不會觸發事件(兄弟攔截了)

     B, 将B 和 C 的 腳本B.cs 和 C.cs重新挂載到B,C上

           1, 點選C的時候A不會觸發事件(被C攔截了)

           2, 和上面一樣點選B,A也不會觸發事件

三, 測試二(傳遞測試)

       1, 特殊需求: 無論點選B或者C都會觸發下面的A

       B.cs 代碼如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class B : MonoBehaviour, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("B click");
        PassEvent(eventData, ExecuteEvents.pointerClickHandler);
    }

    //把事件透下去
    public void PassEvent<T>(PointerEventData data, ExecuteEvents.EventFunction<T> function)
        where T : IEventSystemHandler
    {
        List<RaycastResult> results = new List<RaycastResult>();
        EventSystem.current.RaycastAll(data, results);
        GameObject current = data.pointerCurrentRaycast.gameObject;
        for (int i = 0; i < results.Count; i++)
        {
            if (current != results[i].gameObject)
            {
                ExecuteEvents.Execute(results[i].gameObject, data, function);
            }
        }
    }
}           

C.cs 代碼

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class C : MonoBehaviour, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("C click");
        PassEvent(eventData, ExecuteEvents.pointerClickHandler);
    }


    public void PassEvent<T>(PointerEventData data, ExecuteEvents.EventFunction<T> function)
        where T : IEventSystemHandler
    {
        List<RaycastResult> results = new List<RaycastResult>();
        EventSystem.current.RaycastAll(data, results);
        GameObject current = data.pointerCurrentRaycast.gameObject;
        for (int i = 0; i < results.Count; i++)
        {
            if (current != results[i].gameObject)
            {
                ExecuteEvents.Execute(results[i].gameObject, data, function);
            }
        }
    }
}
           

四, 需求:B不需要Event, 但是要透過B可以觸發A的Event 

     1, 腳本

using UnityEngine;
using UnityEngine.UI;

public class ImageExtends : Image
{
    override public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
    {
        return false;//不攔截, (自己也不會觸發Event)
    }
}
           

    2, 将腳本挂載到B的GameObject上

Unity3D之事件的穿透和傳遞

五, 需求: 關閉A及A的孩子的Event

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class A : MonoBehaviour, IPointerClickHandler, ICanvasRaycastFilter
{
    [SerializeField]
    private bool IsFocus = false;
    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("A click");
    }



    public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
    {
        return IsFocus;
    }
}           

繼續閱讀