• 【Unity3D NGUI】----UI尺寸和位置的调整


    1 尺寸与位置

    通过UIWidget类获取,该类是所有UI元素的基类

    在unity中创建一个sprite,如下图所示

    这里面这个sprite的大小受几个属性的影响,首先是属性面板里的Size,对应的UIWidget成员为width和height字段,然后是其上层节点和自身scale属性。

     

    1.1 局部大小

    public override Vector3[] worldCorners
        {
            get
            {
                Vector2 offset = pivotOffset;
    
                float x0 = -offset.x * mWidth;
                float y0 = -offset.y * mHeight;
                float x1 = x0 + mWidth;
                float y1 = y0 + mHeight;
    
                Transform wt = cachedTransform;
    
                mCorners[0] = wt.TransformPoint(x0, y0, 0f);
                mCorners[1] = wt.TransformPoint(x0, y1, 0f);
                mCorners[2] = wt.TransformPoint(x1, y1, 0f);
                mCorners[3] = wt.TransformPoint(x1, y0, 0f);
    
                return mCorners;
            }
        }

    从上面可以看出局部角点对应的矩形宽和长就等于width和height(mWidth等于width)

    1.2 世界坐标系大小

    所以计算某个UI元素在屏幕上的真实大小应该为

    public override Vector3[] worldCorners
        {
            get
            {
                Vector2 offset = pivotOffset;
    
                float x0 = -offset.x * mWidth;
                float y0 = -offset.y * mHeight;
                float x1 = x0 + mWidth;
                float y1 = y0 + mHeight;
    
                Transform wt = cachedTransform;
    
                mCorners[0] = wt.TransformPoint(x0, y0, 0f);
                mCorners[1] = wt.TransformPoint(x0, y1, 0f);
                mCorners[2] = wt.TransformPoint(x1, y1, 0f);
                mCorners[3] = wt.TransformPoint(x1, y0, 0f);
    
                return mCorners;
            }
        }

    从里面取两个四个角点之间的距离即可算出真实的大小(因为Transform类获取不到derived scale属性,只能获取到localScale属性)

    上面代码中也用到了pivotOffset,该属性对应于在编辑器选中UI元素局部坐标系的原点,默认的情况下该值是(0.5,0.5),表示在UIWidget中的中心,为(0,0)表示在左下角,(1,1)表示在右上角。

    同时根据上面的worldCorners也很好获取该UI元素在屏幕上的位置。这里面世界位置的计算中,可以看出同时用到了定义UI元素时的大小、坐标中心,以及该UI元素的转置矩阵。

    所以说,假如需要改变UI元素的位置,只需改变其转置矩阵里的位置即可。

    1.3 相对于其他元素的位置

    采用通用的计算过程,即假如要计算B相对于A的位置,只需给出A和B的世界坐标PA和PB,那么B相对于A的位置即为 Rba = PB- PA。

    NGUI里对应的代码如下:

     

    public override Vector3[] GetSides (Transform relativeTo)
        {
            Vector2 offset = pivotOffset;
    
            float x0 = -offset.x * mWidth;
            float y0 = -offset.y * mHeight;
            float x1 = x0 + mWidth;
            float y1 = y0 + mHeight;
            float cx = (x0 + x1) * 0.5f;
            float cy = (y0 + y1) * 0.5f;
    
            Transform trans = cachedTransform;
            mCorners[0] = trans.TransformPoint(x0, cy, 0f);
            mCorners[1] = trans.TransformPoint(cx, y1, 0f);
            mCorners[2] = trans.TransformPoint(x1, cy, 0f);
            mCorners[3] = trans.TransformPoint(cx, y0, 0f);
    
            if (relativeTo != null)
            {
                for (int i = 0; i < 4; ++i)
                    mCorners[i] = relativeTo.InverseTransformPoint(mCorners[i]);
            }
            return mCorners;
        }

    1.4 屏幕位置

    上面讨论的位置均是3D空间的位置,而非屏幕上的位置。

    要获取一个UI元素在屏幕上的位置,使用NGUI的摄像头将世界坐标转换到屏幕坐标

    pt=UICamera.currentCamera.WorldToScreenPoint(pt);

    对于置于世界原点的摄像机,它的光轴也穿过世界原点,假如使用

    Vector3 screenPt = cam.WorldToScreenPoint(new Vector3(0,0,cam.nearClipPlane);

    来计算光轴中心点在屏幕上的位置,可以发现算出来的屏幕位置也为屏幕中心,即(Screen.width/2,Screen.height/2,cam.nearClipPlane);

    在NGUI中,2DUI的摄像机是正交摄像机,3D的才是透视摄像机。

    同时正交摄像机中

    屏幕的右上角对应的世界坐标为:

    Vector3 worldPt = cam.ScreenToWorldPoint(newVector3(Screen.width,Screen.height,uiCam.nearClipPlane));

    //worldPt = (cam.size*(Screen.width/Screen.height),cam.size,cam.nearClipPlane);

    左下角的世界坐标为:

    Vector3 worldPt1 = cam.ScreenToWorldPoint(newVector3(0,0,uiCam.nearClipPlane));

    //worldPt = (-cam.size*(Screen.width/Screen.height),-cam.size,cam.nearClipPlane);

    这里面假设的是相机填满整个屏幕,即相机的Rect属性的w和h均为1

     

    2 实例

    2.1 将UI移动屏幕指定像素位置

    usingUnityEngine;
    usingSystem.Collections;
    
    publicclassSetPos:MonoBehaviour {
    
       publicint targetX;
       publicint targetY;
    
       public Camera uiCam;
       private UIWidget ui;
       
       voidStart() {
    
           ui=GetComponent<UIWidget>();
           SetScreenPosition(targetX, targetY);
    }
       voidSetScreenPosition(int x,int y)
       {
           Vector3 targetPos = uiCam.ScreenToWorldPoint(newVector3(x, y, transform.position.z));
           Vector3 dir = targetPos - transform.position;
           transform.Translate(dir);
       }
       voidSetScreenPosition1(int x,int y)
       {
    //使用线性映射计算目标位置
           float w =Screen.width;
           float h =Screen.height;
           float posX = uiCam.orthographicSize* w / h;
           float posY = uiCam.orthographicSize;
           float targetX = x *2* posX / w - posX;
           float targetY = y *2* posY / h - posY;
    
           Vector3 targetPos1 =newVector3(targetX, targetY,0);
           Vector3 dir = targetPos1 - transform.position;
           transform.Translate(dir);      
       }
    
    }
  • 相关阅读:
    【LOJ】#2071. 「JSOI2016」最佳团体
    【LOJ】#2070. 「SDOI2016」平凡的骰子
    【LOJ】#2069. 「SDOI2016」齿轮
    【LOJ】#2068. 「SDOI2016」探险路线
    【LOJ】#2067. 「SDOI2016」硬币游戏
    【LOJ】#2066. 「SDOI2016」墙上的句子
    【LOJ】#2065. 「SDOI2016」模式字符串
    【LOJ】#2064. 「HAOI2016」找相同字符
    【LOJ】#2063. 「HAOI2016」字符合并
    【LOJ】#2062. 「HAOI2016」地图
  • 原文地址:https://www.cnblogs.com/nanwei/p/7149013.html
Copyright © 2020-2023  润新知