浮动Tips的一种制作思路

2023/03 07 20:03
游戏内浮动Tips的制作要求:
点击某感叹号,或者道具,会弹出一个小Tips
点击其它任何地方,会直接关闭此Tips
但点击此Tips内的元素,不会关闭此Tips


制作思路:
如果点击命中Tips面板的“子元素”,则不处理(相当于点了面板内的元素);
如果点击在Tips面板之外,则把Tips面板关闭;

1、使用RectTransformUtility.RectangleContainsScreenPoint函数进行检测
2、检测时,要注意UI相机,如果不是Overlay相机,则需要查找当前的UI相机

public class FloatTipsBackground : MonoBehaviour
{
    private Camera mCamera;
    private bool mCameraInit= false;

    private Camera GetUICamera()
    {
        if (mCameraInit)
        {
            return mCamera;
        }

        mCamera = FindParentUICamera();
        mCameraInit = true;
        return mCamera;
    }

    private Camera FindParentUICamera()
    {
        var parentObj = this.transform.parent;
        for(int i=0; i<50 && parentObj != null; ++i)
        {
            var canvas = parentObj.GetComponent<Canvas>();
            if (canvas != null && canvas.renderMode == RenderMode.ScreenSpaceCamera)
            {
                return canvas.worldCamera;
            }
            parentObj = parentObj.parent;
        }
        return null;
    }

    public void Update()
    {
        Vector3 touchPosition = Input.mousePosition;

#if UNITY_EDITOR || UNITY_STANDALONE
        if (Input.GetMouseButtonDown(0))
        {
            touchPosition = Input.mousePosition;
            HandlerClick(touchPosition);
        }
#else
        if (Input.touchCount > 0 && Input.touches[0].phase == TouchPhase.Began )  
        {
            touchPosition = Input.touches[0].position;
            HandlerClick(touchPosition);
        }
#endif
    }

    public bool PointHitChilds(GameObject parentObject, Vector2 p)
    {
        var camera = GetUICamera();
        var childs = parentObject.GetComponentsInChildren<UnityEngine.UI.Graphic>(false);
        foreach(var child in childs)
        {
            if (child.gameObject == parentObject)
            {
                continue;
            }
            if (RectTransformUtility.RectangleContainsScreenPoint(child.rectTransform, p, camera))
            {
                return true;
            }
        }
        return false;
    }

    private void HandlerClick(Vector3 touchPosition)
    {
        Vector2 p = new Vector2(touchPosition.x, touchPosition.y);
        if (!PointHitChilds(this.gameObject, p))
        {
            this.gameObject.SetActive(false);
        }
    }
}