【原】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; } } }