美文网首页
二、坐标:4、ScreenPointToLocalPointIn

二、坐标:4、ScreenPointToLocalPointIn

作者: GameObjectLgy | 来源:发表于2021-10-09 11:31 被阅读0次
ScreenPointToLocalPointInRectangle

public static bool ScreenPointToLocalPointInRectangle(RectTransform rect, Vector2 screenPoint, Camera cam, out Vector2 localPoint);

  • rect: 对应的 RectTransform 的引用
  • screenPoint: 位置,基于屏幕坐标系
  • cam: 相机的引用,如果Canvas的Render Mode 为 Screen Space - Camera 模式,则需要填入 Render Camera 对应的引用
  • localPoint: rect 本地坐标系下的坐标(原点(0,0)位置受Anchor的影响)

应用1:判断鼠标或者触摸点击位置在UI范围之外,则执行某个动作,比如关闭

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

public class UI_ClickOutsideHide : MonoBehaviour
{
    private Rect m_rect;
    private Camera m_uguiCamera;
    private Transform m_canvas;
    private bool m_canCheck = false;
    private float width = 0;
    private float height = 0;
    private RectTransform rectTrans;

    private List<RectTransform> lstExtraRectTransform = new List<RectTransform>();
    private List<Rect> lstExtraRect = new List<Rect>();
    
    private void Awake()
    {
        this.rectTrans = this.GetComponent<RectTransform>();
    }

    Transform UICanvas
    {
        get
        {
            if (m_canvas == null)
            {
                m_canvas = UIManager.Instance.GetCanvas().transform;
            }

            return m_canvas;
        }
    }

    Camera UGUICamera
    {
        get
        {
            if (m_uguiCamera == null)
            {
                m_uguiCamera = UIManager.Instance.GetCamera();
            }

            return m_uguiCamera;
        }
    }

    void OnEnable()
    {
        m_canCheck = true;
    }

    void OnDisable()
    {
        m_canCheck = false;
    }

    private void OnResize()
    {
        Vector3[] corners = new Vector3[4];
        this.rectTrans.GetWorldCorners(corners);
        float width = Math.Abs(Vector2.Distance(corners[0], corners[3]));
        float height = Math.Abs(Vector2.Distance(corners[0], corners[1]));
        m_rect = new Rect(corners[0].x, corners[0].y, width, height);

        for (var index = 0; index < lstExtraRectTransform.Count; index++)
        {
            var rectTransform = lstExtraRectTransform[index];
            lstExtraRect[index] = GetRect(rectTransform);
        }
    }
    
    private Rect GetRect(RectTransform targetRect)
    {
        var corners = new Vector3[4];
        targetRect.GetWorldCorners(corners);
        var width = Math.Abs(Vector2.Distance(corners[0], corners[3]));
        var height = Math.Abs(Vector2.Distance(corners[0], corners[1]));
        return new Rect(corners[0].x, corners[0].y, width, height);
    }

    // Update is called once per frame
    void Update()
    {
        if (!m_canCheck)
        {
            return;
        }

        if (this.width != this.rectTrans.rect.width && this.height != this.rectTrans.rect.height)
        {
            this.OnResize();
            this.width = this.rectTrans.rect.width;
            this.height = this.rectTrans.rect.height;
        }

        if (Input.GetMouseButtonDown(0) || (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began))
        {
            if (Application.platform == RuntimePlatform.WindowsPlayer ||
                Application.platform == RuntimePlatform.WindowsEditor ||
                Application.platform == RuntimePlatform.WindowsWebPlayer)
            {
                if (EventSystem.current.IsPointerOverGameObject())
                {
                    Vector3 curPos = TransToWorldPos(Input.mousePosition);
                    if (m_rect.Contains(curPos))
                    {
                        return;
                    }

                    for (var index = 0; index < lstExtraRect.Count; index++)
                    {
                        var rect = lstExtraRect[index];
                        if (rect.Contains(curPos))
                        {
                            return;
                        }
                    }
                    gameObject.SetActive(false);
                }
            }
            else if (Application.platform == RuntimePlatform.IPhonePlayer ||
                     Application.platform == RuntimePlatform.Android)
            {
                if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
                {
                    Vector3 curPos = TransToWorldPos(Input.mousePosition);
                    if (m_rect.Contains(curPos))
                    {
                        return;
                    }
                    
                    for (var index = 0; index < lstExtraRect.Count; index++)
                    {
                        var rect = lstExtraRect[index];
                        if (rect.Contains(curPos))
                        {
                            return;
                        }
                    }
                    gameObject.SetActive(false);
                }
            }
        }
    }

    private Vector2 TransToWorldPos(Vector3 mousePosition)
    {
        Vector3 worldPosition;
        RectTransformUtility.ScreenPointToWorldPointInRectangle(UICanvas.GetComponent<RectTransform>(), mousePosition,
            UGUICamera, out worldPosition);
        return worldPosition;
    }

    public void AddExtraOutSide(RectTransform rectTransform)
    {
        if (lstExtraRectTransform.Contains(rectTransform))
        {
            return;
        }
        lstExtraRectTransform.Add(rectTransform);
        lstExtraRect.Add(GetRect(rectTransform));
    }
}

应用2:在Canvas不同的渲染模式(RenderMode)下实现UI跟随3D物体

  • 当Canvas.RenderMode为Screen Space-Overlay时
    利用WorldToScreenPoint(worldPos)将物体的世界坐标转换成屏幕坐标,实时更新UI的坐标:
using UnityEngine;
using System.Collections;

public class FollowWorldObj : MonoBehaviour {
    [SerializeField]
    GameObject worldPos;//3D物体(人物)
    [SerializeField]
    RectTransform rectTrans;//UI元素(如:血条等)
    public Vector2 offset;//偏移量

    // Update is called once per frame
    void Update () {
        Vector2 screenPos=Camera.main.WorldToScreenPoint(worldPos.transform.position);
        rectTrans.position = screenPos + offset;
    }
}
  • 当Canvas.RenderMode为Screen Space-Camera时
    利用RectTransformUtility.ScreenPointToLocalPointInRectangle换算出UI元素在Canvas的2D坐标:

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

public class UI_FollowObj : MonoBehaviour {
    [SerializeField]
    Camera UI_Camera;//UI相机
    [SerializeField]
    RectTransform image;//UI元素
    [SerializeField]
    GameObject obj;//3D物体
    [SerializeField]
    Canvas ui_Canvas;
    // Update is called once per frame
    void Update () {
        UpdateNamePosition();
    }
    /// <summary>
    /// 更新image位置
    /// </summary>
    void UpdateNamePosition()
    {
        Vector2 mouseDown = Camera.main.WorldToScreenPoint(obj.transform.position);
        Vector2 mouseUGUIPos = new Vector2();
        bool isRect = RectTransformUtility.ScreenPointToLocalPointInRectangle(ui_Canvas.transform as RectTransform, mouseDown, UI_Camera, out mouseUGUIPos);
        if (isRect)
        {
            image.anchoredPosition = mouseUGUIPos;
        }
    }
}

相关文章

网友评论

      本文标题:二、坐标:4、ScreenPointToLocalPointIn

      本文链接:https://www.haomeiwen.com/subject/gphqoltx.html