RectAToB组件
发布日期:2022-03-03 10:43:58 浏览次数:3 分类:技术文章

本文共 9622 字,大约阅读时间需要 32 分钟。

                                                                                             RectAToB组件

在游戏开发中经常中经常会有这样的需求,需要一个tips界面在某个图标的旁边显示。于是我写了一个RectAToB 方法 之前写的那一版存在一些问题 这一版本可以应对显示不下的情况智能改变tips位置  以下是全部c#代码   需要的同学可以改一改 

需要特别注意的是某些tips界面如果是生成后会动态调整大小的,可能需要你延后一帧去处理逻辑,避免位置偏差。

using UnityEngine;

using UnityEngine.UI;

#if UNITY_EDITOR

using UnityEditor;
#endif

#if UNITY_EDITOR

[CustomEditor(typeof(RectAToB))]
public class RectAToBEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        if(GUILayout.Button("移动"))
        {
            (target as RectAToB).Move();
        }
    }
}
[ExecuteInEditMode]
#endif
public class RectAToB : MonoBehaviour
{
    public RectTransform wndA;
    public RectTransform wndB;
    private RectTransform canvasRect;
    private Camera m_camera = null;
    public enum POS{
        BOTTOM_LEFT   =1,  // 下左 
        BOTTOM_CENTER, // 下中
        BOTTOM_RIGHT, // 下右 

        UP_LEFT, // 上左 

        UP_RIGHT , // 上右 
        UP_CENTER,

        LEFT_TOP, // 左上

        LEFT_CENTER_UP , // 左上up 补充2个方向 
        LEFT_CENTER_DOWN , // 左上up 补充2个方向 
        LEFT_BOTTOM, // 左下

        RIGHT_TOP , // 右上 

        RIGHT_CENTER_UP , //右中上
        RIGHT_CENTER_DOWN , // 右中下 
        RIGHT_BOTTOM, // 右下 

        CENTER_CENTER , // 中心 

        SCREEN_CENTER, // ui元素中心
    }
    public Vector2 offset;
    public POS m_style = POS.LEFT_TOP;
    public POS m_originStyle; // 最初的设定 tips样式
    private int[] limitArray4;
    private int callCount = 0; // 调用计次 防止死递归调用 许多设计都用用调用计次的概念 比如事件服的设计(防止事件死循环)
    void Awake()
    {
           
        this.canvasRect = GameObject.Find("UGuiSystem/MainCanvas").GetComponent<RectTransform>();
        this.m_camera = GameObject.Find("UGuiSystem").GetComponent<Camera>();
        
    }

    public bool TestOutOfScreen(int pos, Vector2 spos) // 检测是否已经离屏了 

    {
        var epos = (POS)pos;

        if (limitArray4 == null || limitArray4.Length == 0)

        {
            //我们游戏是居中,估计一般主canvas也都是这个规格
            if (canvasRect.pivot.x == 0.5 && canvasRect.pivot.y == 0.5)
            {
                limitArray4 = new int[] { Screen.height / 2, -Screen.width / 2, -Screen.height / 2, Screen.width / 2 };
            }
            else if (canvasRect.pivot.x == 0 && canvasRect.pivot.y == 0)
            {
                limitArray4 = new int[] { Screen.height, 0, 0, Screen.width };
            }
        }
        // Debug.Log("spos.x =" + spos.x.ToString() + ",spos.y =" + spos.y.ToString());
        if (epos == POS.RIGHT_TOP)
        {
            if (spos.x + (1 - wndA.pivot.x) *  wndA.sizeDelta.x > limitArray4[3])
            {
                // Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.LEFT_TOP");
                this.m_style = POS.LEFT_TOP;
                offset.x = -offset.x;
                return false;
            }
            else if (spos.y + (1 - wndA.pivot.y) *  wndA.sizeDelta.y > limitArray4[0])
            {
                //  Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.RIGHT_BOTTOM");
                this.m_style = POS.RIGHT_BOTTOM;
                offset.y = -offset.y;
                return false;
            }
        }
       

        else if (epos == POS.LEFT_TOP)

        {

            if (spos.x - wndA.pivot.x *  wndA.sizeDelta.x < limitArray4[1])

            {
                //  Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.RIGHT_TOP");
                this.m_style = POS.RIGHT_TOP;
                offset.x = -offset.x;
                return false;
            }
            else if (spos.y + (1 - wndA.pivot.y) * wndA.sizeDelta.y > limitArray4[0])
            {
                //  Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.LEFT_BOTTOM");
                this.m_style = POS.LEFT_BOTTOM;
                offset.y = -offset.y;
                return false;
            }
        }

        else if (epos == POS.LEFT_BOTTOM)

        {
            if (spos.x - wndA.pivot.x * wndA.sizeDelta.x < limitArray4[1])
            {
                // Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.RIGHT_BOTTOM");
                this.m_style = POS.RIGHT_BOTTOM;
                offset.x = -offset.x;
                return false;
            }
            else if (spos.y - wndA.pivot.y * wndA.sizeDelta.y < limitArray4[2])
            {
                //  Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.LEFT_TOP");
                this.m_style = POS.LEFT_TOP;
                offset.y = -offset.y;
                return false;
            }
        }
        else if (epos == POS.RIGHT_BOTTOM)
        {

            if (spos.x + (1 - wndA.pivot.x) * wndA.sizeDelta.x > limitArray4[3])

            {
                // Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.LEFT_BOTTOM");
                this.m_style = POS.LEFT_BOTTOM;
                offset.x = -offset.x;
                return false;
            }
            else if (spos.y - wndA.pivot.y * wndA.sizeDelta.y < limitArray4[2])
            {
                // Debug.Log("this.m_style从" + this.m_style.ToString() + "切换到POS.RIGHT_TOP");
                this.m_style = POS.RIGHT_TOP;
                offset.y = -offset.y;
                return false;
            }
        }
       
        else // 只需要适配4个方位,其他的位置可以通过这4个方位做偏移来实现
        {
            return false;
        }

        return true;

    }
    public void Move()
    {
        this.m_style = this.m_originStyle;
        callCount = 0; 
        if (wndA == null || wndB == null)
        {
            return;
        }
        if(m_camera == null)
        {
            this.m_camera = GameObject.Find("UGuiSystem").GetComponent<Camera>();
        }
           
        if(m_camera == null)
        {
            return;
        }
        if (this.canvasRect == null)
        {
            this.canvasRect = GameObject.Find("UGuiSystem/MainCanvas").GetComponent<RectTransform>();
        }
        if(this.canvasRect == null)
        {
            return;
        }
        if(wndA.anchorMin.x != 0.5f || wndA.anchorMin.y != 0.5f || 
            wndA.anchorMax.x != 0.5f || wndA.anchorMax.y != 0.5f)
        {
            //后续有时间再去处理不同anchorMin or Max的情况下对应的离屏测试 
            rktLogUtil.GLog("RectAToB 错误 请确保wndA的坐标系统是以图元的中心为中心");
            return;
        }
            //获取目标窗口的世界坐标
            var worldB = Vector3.zero;
        RectTransformUtility.ScreenPointToWorldPointInRectangle(
            canvasRect,
            m_camera.WorldToScreenPoint(wndB.position),
            m_camera,
            out worldB
            );

        wndA.transform.position = worldB;

        MoveImp();
       // Debug.Log("A的最终ui" + wndA.anchoredPosition);
    }

    private void MoveImp()

    {
        callCount = callCount + 1;
        if (callCount > 4)
        {
            //如果4个离屏测试都未能通过那么应该按原始tips来做 或者指定一个坐标去做 考虑一个偏移 
            var worldB = Vector3.zero;
            RectTransformUtility.ScreenPointToWorldPointInRectangle(
                canvasRect,
                m_camera.WorldToScreenPoint(canvasRect.position),
                m_camera,
                out worldB
                );
            this.m_style = POS.SCREEN_CENTER; // 方便debug
            wndA.transform.position = worldB;
            var atoScreenCenterOffset = GetPosAnchoredPosition((int)POS.SCREEN_CENTER);
            SetAnchoredPosition(wndA.anchoredPosition + atoScreenCenterOffset + offset);
            return;
        }
         var atoBoffset = GetPosAnchoredPosition((int)this.m_style);
        //   Debug.Log("A的世界" + wndA.transform.position + "A的ui" + wndA.anchoredPosition + "atoBoffset =" + atoBoffset);
        var finalPos = wndA.anchoredPosition + atoBoffset + offset;
        if (TestOutOfScreen((int)m_style, finalPos))
        {
            SetAnchoredPosition(wndA.anchoredPosition + atoBoffset + offset);
        }
        else
        {
            MoveImp();
        }
    }
    public void SetStyle(int pos)
    {
        m_originStyle = (POS)pos;
        this.m_style = (POS)pos;
    }

    public int GetStyle()

    {
        return (int)this.m_style;
    }

    public void SetAnchoredPosition(Vector2 pos) // 暴露给外部lua方便扩展 

    {
        wndA.anchoredPosition =  pos;
       
    }

    public Vector2 GetPosAnchoredPosition(int st) // 暴露给外部lua

    {
        var style = (POS)st;
        Vector2 atoBoffset = Vector2.zero;
        if (style == POS.LEFT_TOP)
        {
            atoBoffset.x = (wndA.pivot.x - 1) * wndA.sizeDelta.x - (wndB.pivot.x) * wndB.sizeDelta.x;
            atoBoffset.y = (1 - wndB.pivot.y) * wndB.sizeDelta.y + (wndA.pivot.y ) * wndA.sizeDelta.y;
        }
        else if (style == POS.RIGHT_TOP)
        {
            atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 1) * wndB.sizeDelta.x;
            atoBoffset.y = (1 - wndB.pivot.y) * wndB.sizeDelta.y + (wndA.pivot.y) * wndA.sizeDelta.y;
        }

        else if (style == POS.LEFT_BOTTOM)

        {
            atoBoffset.x = (wndA.pivot.x - 1) * wndA.sizeDelta.x - (wndB.pivot.x) * wndB.sizeDelta.x;
            atoBoffset.y = (-wndB.pivot.y) * wndB.sizeDelta.y - (1 - wndA.pivot.y) * wndA.sizeDelta.y;
        }
        else if (style == POS.RIGHT_BOTTOM)
        {
            atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 1) * wndB.sizeDelta.x;
            atoBoffset.y = (-wndB.pivot.y) * wndB.sizeDelta.y -  (1 - wndA.pivot.y) * wndA.sizeDelta.y;
        }
        else if (style == POS.SCREEN_CENTER)
        {
            atoBoffset.x = (wndA.pivot.x -0.5f) * wndA.sizeDelta.x ;
            atoBoffset.y = (wndA.pivot.y - 0.5f) * wndA.sizeDelta.y;
        }
        else if (style == POS.UP_LEFT)
        {
            atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x) * wndB.sizeDelta.x;
            atoBoffset.y = (1 - wndB.pivot.y) * wndB.sizeDelta.y + (wndA.pivot.y) * wndA.sizeDelta.y;
        }
        else if (style == POS.BOTTOM_LEFT)
        {
            atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x) * wndB.sizeDelta.x;
            atoBoffset.y = (1 - wndB.pivot.y - 1) * wndB.sizeDelta.y + (wndA.pivot.y - 1) * wndA.sizeDelta.y;
        }
        else if (style == POS.LEFT_CENTER_UP)
        {
            atoBoffset.x = (wndA.pivot.x - 1) * wndA.sizeDelta.x - (wndB.pivot.x) * wndB.sizeDelta.x;
            atoBoffset.y = (1 - wndB.pivot.y - 0.5f) * wndB.sizeDelta.y + (wndA.pivot.y) * wndA.sizeDelta.y;
        }
        else if (style == POS.LEFT_CENTER_DOWN)
        {
            atoBoffset.x = (wndA.pivot.x - 1) * wndA.sizeDelta.x - (wndB.pivot.x) * wndB.sizeDelta.x;
            atoBoffset.y = (1 - wndB.pivot.y - 0.5f) * wndB.sizeDelta.y + (wndA.pivot.y - 1) * wndA.sizeDelta.y;
        }
        else if (style == POS.RIGHT_CENTER_UP)
        {
            atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 1) * wndB.sizeDelta.x;
            atoBoffset.y = (1 - wndB.pivot.y - 0.5f) * wndB.sizeDelta.y + (wndA.pivot.y) * wndA.sizeDelta.y;
        }
        else if (style == POS.RIGHT_CENTER_DOWN)
        {
            atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 1) * wndB.sizeDelta.x;
            atoBoffset.y = (1 - wndB.pivot.y - 0.5f) * wndB.sizeDelta.y + (wndA.pivot.y - 1) * wndA.sizeDelta.y;
        }

        else if (style == POS.UP_CENTER)

        {
            atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 0.5f) * wndB.sizeDelta.x;
            atoBoffset.y = (1 - wndB.pivot.y) * wndB.sizeDelta.y + (wndA.pivot.y) * wndA.sizeDelta.y;
        }
        else if (style == POS.BOTTOM_CENTER)
        {
            atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 0.5f) * wndB.sizeDelta.x;
            atoBoffset.y = (1 - wndB.pivot.y - 1) * wndB.sizeDelta.y + (wndA.pivot.y - 1) * wndA.sizeDelta.y;
        }
        else if (style == POS.CENTER_CENTER)
        {
            atoBoffset.x = (wndA.pivot.x - 0.5f) * wndA.sizeDelta.x - (wndB.pivot.x - 0.5f) * wndB.sizeDelta.x;
            atoBoffset.y = (wndB.pivot.y + 0.5f) * wndB.sizeDelta.y + (wndA.pivot.y - 0.5f) * wndA.sizeDelta.y;
        }
        else if (style == POS.UP_RIGHT)
        {
            atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 1) * wndB.sizeDelta.x;
            atoBoffset.y = (1 - wndB.pivot.y) * wndB.sizeDelta.y + (wndA.pivot.y) * wndA.sizeDelta.y;
        }
        else if (style == POS.BOTTOM_RIGHT)
        {
            atoBoffset.x = (wndA.pivot.x) * wndA.sizeDelta.x - (wndB.pivot.x - 1) * wndB.sizeDelta.x;
            atoBoffset.y = (1 - wndB.pivot.y - 1) * wndB.sizeDelta.y + (wndA.pivot.y - 1) * wndA.sizeDelta.y;
        }
        return atoBoffset;
    }

}

转载地址:https://blog.csdn.net/yangjie6898862/article/details/109692799 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:DragImage拖拽赋值组件
下一篇:unity 智能tips组件UITipPos

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月24日 14时06分16秒