【原】NGUI中的UIAnchor脚本功能

UIAnchor的功能是把对象锚定在屏幕的边缘(左上,左中,左下,上,中,下,右上,右中,右下),或缩放物体使其匹配屏幕的尺寸。

在1.90版本后,拉长(缩放)的功能被放到UIStretch中,UIAnchor的功能更单一了,就是给对象定位。

 

借用《【Unity插件】NGUI核心组件之UIAnchor》文章中的内容:

NGUI:UIAnchor

Anchor脚本可以用来实现多个目的,这些在Example0里面都有用到。

1. 只要提供一个half-pixel偏移量,它可以让一个控件的位置在Windows系统上精确的显示出来(只有这个Anchor的子控件会受到影响)

2. 如果挂载到一个对象上,那么他可以将这个对象依附到屏幕的角落或者边缘

参数

UI Camera 是渲染这些对象的摄像机,如果没有手动设置,它会自动设置一个场景中的摄像机

Side 设置锚点,分别可以设置4个角,4个边和中心点

Half Pixel Offset 可以让对象在windows系统上显示的时候,有半个像素的偏移量。2D UI界面需要勾选上这个

Depth Offset 用来调整UIAnchor计算出来的位置的深度。它主要作用于基于透视的摄像机。这个值是世界坐标,与摄像机的远近裁切面类似

Relative Offset 相对偏移量 让你可以为物体设置以屏幕半分比为单位的偏移量

Tips

1. 如果一个对象上面挂载了一个UIAnchor,那么他的transform的值不能被手动修改-他们是被脚本控制的。如果你想对锚点加一个偏移量,那么给他添加一个子物体。举例来说,为了保证你的控件在一直在(100,100)的位置,你的对象结构应该是:UI->Anchor->Offset->Widget。

2. 如果你想将一个控件的位置设置为屏幕左边25%的位置,你可以将他设置为一个UIAnchor的子物体,这个UIAnchor的Side设置为Left,Relateive Offset 的X值设置为0.25。

 

脚本运行的前提是在UIRoot中能找到Camera对象,如果找不到就不会有任何效果。

定位只考虑屏幕的尺寸,并不考虑节点下的对象尺寸。默认情况下,UIAnchor附着在一个空的GameObject,脚本获得Camera的pixelRect属性(相机被渲染到屏幕像素中的位置),通过如下代码定位到屏幕边缘的8个像素点和1个中心像素点上。

 1             Rect rect = uiCamera.pixelRect;
 2             float cx = (rect.xMin + rect.xMax) * 0.5f;
 3             float cy = (rect.yMin + rect.yMax) * 0.5f;
 4             Vector3 v = new Vector3(cx, cy, depthOffset);
 5 
 6             if (side != Side.Center)
 7             {
 8                 if (side == Side.Right || side == Side.TopRight || side == Side.BottomRight)
 9                 {
10                     v.x = rect.xMax;
11                 }
12                 else if (side == Side.Top || side == Side.Center || side == Side.Bottom)
13                 {
14                     v.x = cx;
15                 }
16                 else
17                 {
18                     v.x = rect.xMin;
19                 }
20 
21                 if (side == Side.Top || side == Side.TopRight || side == Side.TopLeft)
22                 {
23                     v.y = rect.yMax;
24                 }
25                 else if (side == Side.Left || side == Side.Center || side == Side.Right)
26                 {
27                     v.y = cy;
28                 }
29                 else
30                 {
31                     v.y = rect.yMin;
32                 }
33             }

所以,如果在UIAnchor下的Panel中创建一个Button,默认情况把UIAnchor定位到左下,Button只会奇怪的露出1/4。因为Button的中心随着UIAnchor被定位在屏幕的左下角的像素上了。

 

另一个有用的参数是relativeOffset,这是个百分比参数。屏幕的宽和高被乘以偏移百分比后,加到记录屏幕中点的变量上,用有效的Camera转为对应的世界度坐标,并重新给UIAnchor来定位:

 1             float screenWidth  = rect.width;
 2             float screenHeight = rect.height;
 3 
 4             v.x += relativeOffset.x * screenWidth;
 5             v.y += relativeOffset.y * screenHeight;
 6 
 7             if (uiCamera.orthographic)
 8             {
 9                 v.x = Mathf.RoundToInt(v.x);
10                 v.y = Mathf.RoundToInt(v.y);
11 
12                 if (halfPixelOffset && mIsWindows)
13                 {
14                     v.x -= 0.5f;
15                     v.y += 0.5f;
16                 }
17             }
18 
19             // Convert from screen to world coordinates, since the two may not match (UIRoot set to manual size)
20             v = uiCamera.ScreenToWorldPoint(v);
21 
22             // Wrapped in an 'if' so the scene doesn't get marked as 'edited' every frame
23             if (mTrans.position != v) mTrans.position = v;

 

UIAnchor的完整代码:

//----------------------------------------------
//            NGUI: Next-Gen UI kit
// Copyright © 2011-2012 Tasharen Entertainment
//----------------------------------------------

using UnityEngine;

/// <summary>
/// This script can be used to anchor an object to the side of the screen,
/// or scale an object to always match the dimensions of the screen.
/// </summary>

[ExecuteInEditMode]
[AddComponentMenu("NGUI/UI/Anchor")]
public class UIAnchor : MonoBehaviour
{
    public enum Side
    {
        BottomLeft,
        Left,
        TopLeft,
        Top,
        TopRight,
        Right,
        BottomRight,
        Bottom,
        Center,
    }

    public Camera uiCamera = null;
    public Side side = Side.Center;
    public bool halfPixelOffset = true;
    public float depthOffset = 0f;
    public Vector2 relativeOffset = Vector2.zero;

    // Stretching is now done by a separate script -- UIStretch, as of version 1.90.
    [HideInInspector][SerializeField] bool stretchToFill = false;

    Transform mTrans;
    bool mIsWindows = false;

    /// <summary>
    /// Legacy support.
    /// </summary>

    void Start ()
    {
        if (stretchToFill)
        {
            stretchToFill = false;

            UIStretch stretch = gameObject.AddComponent<UIStretch>();
            stretch.style = UIStretch.Style.Both;
            stretch.uiCamera = uiCamera;
        }
    }

    /// <summary>
    /// Automatically find the camera responsible for drawing the widgets under this object.
    /// </summary>

    void OnEnable ()
    {
        mTrans = transform;

        mIsWindows = (Application.platform == RuntimePlatform.WindowsPlayer ||
            Application.platform == RuntimePlatform.WindowsWebPlayer ||
            Application.platform == RuntimePlatform.WindowsEditor);

        if (uiCamera == null) uiCamera = NGUITools.FindCameraForLayer(gameObject.layer);
    }

    /// <summary>
    /// Anchor the object to the appropriate point.
    /// </summary>

    void Update ()
    {
        if (uiCamera != null)
        {
            Rect rect = uiCamera.pixelRect;
            float cx = (rect.xMin + rect.xMax) * 0.5f;
            float cy = (rect.yMin + rect.yMax) * 0.5f;
            Vector3 v = new Vector3(cx, cy, depthOffset);

            if (side != Side.Center)
            {
                if (side == Side.Right || side == Side.TopRight || side == Side.BottomRight)
                {
                    v.x = rect.xMax;
                }
                else if (side == Side.Top || side == Side.Center || side == Side.Bottom)
                {
                    v.x = cx;
                }
                else
                {
                    v.x = rect.xMin;
                }

                if (side == Side.Top || side == Side.TopRight || side == Side.TopLeft)
                {
                    v.y = rect.yMax;
                }
                else if (side == Side.Left || side == Side.Center || side == Side.Right)
                {
                    v.y = cy;
                }
                else
                {
                    v.y = rect.yMin;
                }
            }

            float screenWidth  = rect.width;
            float screenHeight = rect.height;

            v.x += relativeOffset.x * screenWidth;
            v.y += relativeOffset.y * screenHeight;

            if (uiCamera.orthographic)
            {
                v.x = Mathf.RoundToInt(v.x);
                v.y = Mathf.RoundToInt(v.y);

                if (halfPixelOffset && mIsWindows)
                {
                    v.x -= 0.5f;
                    v.y += 0.5f;
                }
            }

            // Convert from screen to world coordinates, since the two may not match (UIRoot set to manual size)
            v = uiCamera.ScreenToWorldPoint(v);

            // Wrapped in an 'if' so the scene doesn't get marked as 'edited' every frame
            if (mTrans.position != v) mTrans.position = v;
        }
    }
}
View Code

 

原文地址:http://www.cnblogs.com/basecn/p/NGUI_UIAnchor.html 

posted @ 2013-12-26 14:31  BaseCN  阅读(1815)  评论(0编辑  收藏  举报