zoukankan      html  css  js  c++  java
  • NGUI锚定系统:UIAnchorUIRect

    一、UIAnchor:非UIRect对象的坐标适配。
    NGUI的Anchor锚点:
    public enum Side
    {
       BottomLeft,
       Left,
       TopLeft,
       Top,
       TopRight,
       Right,
       BottomRight,
       Bottom,
       Center,
    }
    锚定坐标的计算:mRect{x = xMin, y = yMin, width = xMax - xMin, height = yMax - yMin}.
    1.计算出mRect,获取mRect的中心点坐标。
    2.根据side值获取对象将使用的基础锚定坐标v。
    3.根据pixelOffset、relativeOffset等预设的偏移信息修正坐标v。
    4.坐标转换,赋值。该功能无法修改渲染对象的大小。
    //只截取核心代码段
    float cx = (mRect.xMin + mRect.xMax) * 0.5f;//锚定目标的中心点,mRect锚定目标的信息。
    float cy = (mRect.yMin + mRect.yMax) * 0.5f;
    Vector3 v = new Vector3(cx, cy, 0f);//当前对象将被设置的坐标。
     
    if (side != Side.Center)
    {
       if (side == Side.Right || side == Side.TopRight || side == Side.BottomRight) v.x = mRect.xMax;
       else if (side == Side.Top || side == Side.Center || side == Side.Bottom) v.x = cx;
       else v.x = mRect.xMin;
     
       if (side == Side.Top || side == Side.TopRight || side == Side.TopLeft) v.y = mRect.yMax;
       else if (side == Side.Left || side == Side.Center || side == Side.Right) v.y = cy;
       else v.y = mRect.yMin;
    }
     
    float width = mRect.width;
    float height = mRect.height;
     
    v.x += pixelOffset.x + relativeOffset.x * width;//偏移值,pixelOffset绝对像素,relativeOffset相对比例
    v.y += pixelOffset.y + relativeOffset.y * height;
     
    v.x = Mathf.Round(v.x);
    v.y = Mathf.Round(v.y);
     
    //坐标转换
    if (pc != null)
    {
       v = pc.cachedTransform.TransformPoint(v);
    }
    else if (container != null)
    {
       Transform t = container.transform.parent;
       if (t != null) v = t.TransformPoint(v);
    }
    v.z = mTrans.position.z;
    if (mTrans.position != v) mTrans.position = v;//坐标设置
    举个例子:在下面的图片中,小图锚定到大图中,铆钉信息如下:
    小图坐标计算:这边的tf坐标根据Side的枚举值得出。
    X = tf.x + relativeOffset.x * width + pixelOffset.x = -640 + 0.2*1280 + 100 = -284
    Y = tf.y + relativeOffset.y * height+ pixelOffset.y =360 +(-0.2)*720 + (-100 )= 116
    二、UIRect:渲染对象基类。
    1、AnchorPoint:锚定功能。
    保存了锚点相关的target elativeabsolute等核心属性,以及封装了部分公共方法。
    2、重要属性。
    1. leftAnchor/rightAnchor/bottomAnchor/topAnchor:四个角的锚点。
    默认leftottom的relative为0,top/right的relative为1.
    Inspector中设置的是absolute值。
    1. mUpdateFrame:当前更新帧,避免重复更新。
    1. mUpdateAnchors:标记当前帧是否要更新锚点。
    1. cachedGameObject/cachedTransform/parent/root:缓存相关节点。
    3.重要方法。
    1. UpdateAnchorsInternal():更新锚点信息,包括更新锚点target的rect,该方法在Mono的Update方法执行。而NGUI的渲染逻辑在LateUpdate执行,确保了在渲染时获取到最新的锚点信息及最终的渲染范围。
    1. GetSides:虚方法,用于获取四条边相对于某个Transform的坐标,具体实现在子类(UIWidget,UILabel,UIPanel)。例如UIWidget实际取到的是:
    /// <summary>
    /// Get the sides of the rectangle relative to the specified transform.
    /// The order is left, top, right, bottom.
    /// </summary>
     
    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. OnAnchor:虚方法,核心方法。定义如何根据锚点信息更新自身位置及大小,具体实现在子类(UIWidget,UILabel,UIPanel),在UpdateAnchorsInternal里调用。以UIWidget为例:
    protected override void OnAnchor ()
    {
       float lt, bt, rt, tt;
       Transform trans = cachedTransform;
       Transform parent = trans.parent;
       Vector3 pos = trans.localPosition;
       Vector2 pvt = pivotOffset;
     
       // Attempt to fast-path if all anchors match
       if (leftAnchor.target == bottomAnchor.target &&
          leftAnchor.target == rightAnchor.target &&
          leftAnchor.target == topAnchor.target)
       {
          Vector3[] sides = leftAnchor.GetSides(parent);
     
          if (sides != null)
          {
             lt = NGUIMath.Lerp(sides[0].x, sides[2].x, leftAnchor.relative) + leftAnchor.absolute;
             rt = NGUIMath.Lerp(sides[0].x, sides[2].x, rightAnchor.relative) + rightAnchor.absolute;
             bt = NGUIMath.Lerp(sides[3].y, sides[1].y, bottomAnchor.relative) + bottomAnchor.absolute;
             tt = NGUIMath.Lerp(sides[3].y, sides[1].y, topAnchor.relative) + topAnchor.absolute;
          }
       }
     
       // Calculate the new position, width and height
       Vector3 newPos = new Vector3(Mathf.Lerp(lt, rt, pvt.x), Mathf.Lerp(bt, tt, pvt.y), pos.z);
       newPos.x = Mathf.Round(newPos.x);
       newPos.y = Mathf.Round(newPos.y);
     
       int w = Mathf.FloorToInt(rt - lt + 0.5f);
       int h = Mathf.FloorToInt(tt - bt + 0.5f);
     
       // Maintain the aspect ratio if requested and possible
       if (keepAspectRatio != AspectRatioSource.Free && aspectRatio != 0f)
       {
          if (keepAspectRatio == AspectRatioSource.BasedOnHeight)
          {
             w = Mathf.RoundToInt(h * aspectRatio);
          }
          else h = Mathf.RoundToInt(w / aspectRatio);
       }
     
       // Don't let the width and height get too small
       if (w < minWidth) w = minWidth;
       if (h < minHeight) h = minHeight;
     
       // Update the position if it has changed
       if (Vector3.SqrMagnitude(pos - newPos) > 0.001f)
       {
          cachedTransform.localPosition = newPos;
          if (mIsInFront) mChanged = true;
       }
     
       // Update the width and height if it has changed
       if (mWidth != w || mHeight != h)
       {
          mWidth = w;
          mHeight = h;
          if (mIsInFront) mChanged = true;
          if (autoResizeBoxCollider) ResizeCollider();
       }
    }
    4.锚点具体步骤:
    1. 获取对应的锚点对象target的渲染区域sides。例如下面的Texture的Sides的4个点。
    1. 通过leftAnchor/rightAnchor/bottomAnchor/topAnchor确定四个边的坐标,例如左边坐标计算是
    lt = NGUIMath.Lerp(sides[0].x, sides[2].x, leftAnchor.relative) + leftAnchor.absolute;
    static public float Lerp (float from, float to, float factor) 
    { 
        return from * (1f - factor) + to * factor; 
    }
    • 这边leftAnchor.relative=0是在UIRectEditor.DrawAnchorTransform设置的,同理rightAnchor.relative= 1。
    3.通过上一步计算的四条边和Pivot计算最终的显示坐标。
    Vector3 newPos = new Vector3(Mathf.Lerp(lt, rt, pvt.x), Mathf.Lerp(bt, tt, pvt.y), pos.z);
    4.通过4条边计算渲染区域的大小。
    int w = Mathf.FloorToInt(rt - lt + 0.5f);
    int h = Mathf.FloorToInt(tt - bt + 0.5f);
    5.通过前面的知识点,NGUI通过矩形的4个点确定最终的渲染区域(大小及坐标)。锚点系统通过动态修改矩形的四条边,从而实现对最终渲染矩形坐标、大小的修改。
     
     
     
  • 相关阅读:
    Oracle And子句
    Oracle Where(条件)子句用法
    extern “C”的作用详解
    函数重载
    给变量起名字的网站。
    同步异步
    CCS5.5安装破解过程
    Semaphore_pend();阻塞函数
    vi常用命令
    Linux下VI操作命令
  • 原文地址:https://www.cnblogs.com/wang-jin-fu/p/13508990.html
Copyright © 2011-2022 走看看