Radiographic penetration problems often arise when using UGUI in a mixture of 2D and 3D scenes. In the 3D scene, we obtain the coordinates of mouse click in the scene by radiographic detection. The usual code is as follows:

if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitinfo;
            bool isCollider =  Physics.Raycast(ray, out hitinfo);
            if(isCollider&&hitinfo.collider.tag == Tags.Ground)
            {
 				//do some thingdir = hitinfo.point; }}Copy the code

However, when games like RPG are made, a Canvas is usually placed under the Camera component to render the UGUI. Such A UI interface will have multiple buttons for interaction. ❌ is a problem. For example, the function of a button is to open the backpack, and the radiography is used to generate a small tree in the scene according to where the button is clicked. When we click the button, the method of opening the backpack is triggered, and the effect of the ray in the scene also appears. Click the backpack button, and you don’t need to create a tree. Such problems need to be addressed now. Many functions for radiography have been officially encapsulated in the UGUI. There’s a Raycast method in the GraphicRaycaster class, which adds whatever ray hits to the List resultAppendList, and the RaycastResult object contains a lot of information about the properties of the object being tested, so I’m not going to use it here, As long as we detect a component contact with UIGUI, we don’t perform the custom ray interaction with the scene. Here is the source code for decompiled DLL:

public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
        {
            if (canvas == null)
            {
                return;
            }

            IList<Graphic> graphicsForCanvas = GraphicRegistry.GetGraphicsForCanvas(canvas);
            if (graphicsForCanvas == null || graphicsForCanvas.Count == 0)
            {
                return;
            }

            Camera eventCamera = this.eventCamera;
            intnum = (canvas.renderMode ! =0 && !(eventCamera == null))? eventCamera.targetDisplay : canvas.targetDisplay; Vector3 vector = Display.RelativeMouseAt(eventData.position);if(vector ! = Vector3.zero) {int num2 = (int)vector.z;
                if(num2 ! = num) {return; }}else
            {
                vector = eventData.position;
            }

            Vector2 vector2;
            if (eventCamera == null)
            {
                float num3 = Screen.width;
                float num4 = Screen.height;
                if (num > 0 && num < Display.displays.Length)
                {
                    num3 = Display.displays[num].systemWidth;
                    num4 = Display.displays[num].systemHeight;
                }

                vector2 = new Vector2(vector.x / num3, vector.y / num4);
            }
            else
            {
                vector2 = eventCamera.ScreenToViewportPoint(vector);
            }

            if (vector2.x < 0f || vector2.x > 1f || vector2.y < 0f || vector2.y > 1f)
            {
                return;
            }

            float num5 = float.MaxValue;
            Ray r = default(Ray);
            if(eventCamera ! =null)
            {
                r = eventCamera.ScreenPointToRay(vector);
            }

            if(canvas.renderMode ! =0&& blockingObjects ! =0)
            {
                float f = 100f;
                if(eventCamera ! =null)
                {
                    float z = r.direction.z;
                    f = (Mathf.Approximately(0f, z) ? float.PositiveInfinity : Mathf.Abs((eventCamera.farClipPlane - eventCamera.nearClipPlane) / z));
                }

                if((blockingObjects == BlockingObjects.ThreeD || blockingObjects == BlockingObjects.All) && ReflectionMethodsCache.Singleton.raycast3D ! =null)
                {
                    RaycastHit[] array = ReflectionMethodsCache.Singleton.raycast3DAll(r, f, m_BlockingMask);
                    if(array.Length ! =0)
                    {
                        num5 = array[0].distance; }}if((blockingObjects == BlockingObjects.TwoD || blockingObjects == BlockingObjects.All) && ReflectionMethodsCache.Singleton.raycast2D ! =null)
                {
                    RaycastHit2D[] array2 = ReflectionMethodsCache.Singleton.getRayIntersectionAll(r, f, m_BlockingMask);
                    if(array2.Length ! =0)
                    {
                        num5 = array2[0].distance;
                    }
                }
            }

            m_RaycastResults.Clear();
            Raycast(canvas, eventCamera, vector, graphicsForCanvas, m_RaycastResults);
            int count = m_RaycastResults.Count;
            for (int i = 0; i < count; i++)
            {
                GameObject gameObject = m_RaycastResults[i].gameObject;
                bool flag = true;
                if (ignoreReversedGraphics)
                {
                    if (eventCamera == null)
                    {
                        Vector3 rhs = gameObject.transform.rotation * Vector3.forward;
                        flag = (Vector3.Dot(Vector3.forward, rhs) > 0f);
                    }
                    else
                    {
                        Vector3 b = eventCamera.transform.rotation * Vector3.forward * eventCamera.nearClipPlane;
                        flag = (Vector3.Dot(gameObject.transform.position - eventCamera.transform.position - b, gameObject.transform.forward) >= 0f); }}if(! flag) {continue;
                }

                float num6 = 0f;
                Transform transform = gameObject.transform;
                Vector3 forward = transform.forward;
                if (eventCamera == null || canvas.renderMode == RenderMode.ScreenSpaceOverlay)
                {
                    num6 = 0f;
                }
                else
                {
                    num6 = Vector3.Dot(forward, transform.position - r.origin) / Vector3.Dot(forward, r.direction);
                    if (num6 < 0f)
                    {
                        continue; }}if(! (num6 >= num5)) { RaycastResult raycastResult =default(RaycastResult);
                    raycastResult.gameObject = gameObject;
                    raycastResult.module = this; raycastResult.distance = num6; raycastResult.screenPosition = vector; raycastResult.displayIndex = num; raycastResult.index = resultAppendList.Count; raycastResult.depth = m_RaycastResults[i].depth; raycastResult.sortingLayer = canvas.sortingLayerID; raycastResult.sortingOrder = canvas.sortingOrder; raycastResult.worldPosition = r.origin + r.direction * num6; raycastResult.worldNormal = -forward; RaycastResult item = raycastResult; resultAppendList.Add(item); }}}Copy the code

The specific implementation method is as follows, learning www.cnblogs.com/fly-100/p/4… This blog post

bool CheckGuiRaycastObjects()
    {
        PointerEventData eventData = new PointerEventData(eventSystem);
        eventData.pressPosition = Input.mousePosition;
        eventData.position = Input.mousePosition;

        List<RaycastResult> list = new List<RaycastResult>();
        graphicRaycaster.Raycast(eventData, list);
        return list.Count > 0;
    }
Copy the code

These two variables correspond to the GraphicRaycaster component in the Canvas and the EventSystem component in the “EventSystem” that is automatically generated when the UI is created.

Use two public variables to specify both components.



Method of use

When a UGUI click is detected, the custom ray is no longer detected to avoid problems.

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            if (CheckGuiRaycastObjects())
            {
                return;
            }
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitinfo;
            bool isCollider =  Physics.Raycast(ray, out hitinfo);
            if(isCollider&&hitinfo.collider.tag == Tags.Ground) { dir = hitinfo.point; }}}Copy the code