NGUI之位置尺寸相关

这篇博客详细介绍了NGUI中UI元素的位置和尺寸计算,包括局部大小、世界坐标系大小、相对于其他元素的位置和屏幕位置。通过UIWidget类和Transform的属性,解释了如何在Unity中调整和定位UI元素,并提供了实例演示如何移动UI和实现滚动效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 尺寸与位置

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



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




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

1.1 局部大小

public override Vector3[] localCorners
	{
		get
		{
			Vector2 offset = pivotOffset;

			float x0 = -offset.x * mWidth;
			float y0 = -offset.y * mHeight;
			float x1 = x0 + mWidth;
			float y1 = y0 + mHeight;

			mCorners[0] = new Vector3(x0, y0);
			mCorners[1] = new Vector3(x0, y1);
			mCorners[2] = new Vector3(x1, y1);
			mCorners[3] = new Vector3(x1, y0);

			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);      
   }

}



上面两个函数可以实现相同的效果


2.1 简单滚动效果


usingUnityEngine;
usingSystem.Collections;

//实现当前UI元素在屏幕上来回滚动
publicclassScrollSprite:MonoBehaviour {

   public Camera uiCam;  
   public float topY ;
   voidStart()
   {        
       Vector3 scrollV = uiCam.ScreenToWorldPoint(newVector3(transform.position.x,Screen.height,transform.position.z));               
       topY= uiCam.orthographicSize;             
   }

   // Update is called once per frame
   voidUpdate()
   {
       
       Vector3 pos = transform.position;     
       if(pos.y> topY)
       {
           transform.Translate(newVector3(0,-2*topY,0));
       }
       else
       {
           transform.Translate(newVector3(0,2*Time.deltaTime,0));
       }
   }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值