遇到问题
通过一个世界坐标,在屏幕对应位置生成Ui。
记录原因
在没遇到这个问题之前也听过类似的需求,想法也很简单,就是有个方法Camera.main.WorldToScreenPoint();世界坐标转屏幕坐标,然后克隆物体并赋值。
如图示方法
然而,在实际操作的时候却发现,无论怎么操作,都无法达到所需要的效果。这就让我对自己的云代码能力产生了怀疑。
之后我通过对比输出的屏幕坐标和我需要显示的物体位置不断对比,发现我对这几种概念完全懵了。屏幕坐标?世界坐标?视口坐标?
重点
通过查询很多材料。我意识到原来Unity中有四种坐标系
1 .World Space(世界坐标):三维空间坐标,Vector3。
2.Screen Space(屏幕坐标):以像素来定义的,以屏幕的左下角为(0,0)点,右上角为(Screen.width,Screen.height),Z的位置是以相机的世界单位来衡量的。
3.ViewPort Space(视口坐标):视口坐标是标准的和相对于相机的。相机的左下角为(0,0)点,右上角为(1,1)点,Z的位置是以相机的世界单位来衡量的。
4.UGUI界面的坐标系:与锚点有关,锚点所在位置即为(0,0)。
那么问题就出来了。
我们的需求是通过一个世界坐标,在屏幕对应位置生成Ui。所以我主观的认为这个屏幕对应位置即为屏幕坐标。然而事实上在3D的场景中屏幕显示的位置就是物体所在的位置。那么,这个屏幕的对应位置应该Ui的坐标。所以需求其实应该是通过一个世界坐标,在Ui的对应位置上生成一个Ui。
那么问题就好解决了。以下是我用到的方法作为参考,参数都有说明。
/// <summary>
/// 世界坐标转屏幕坐标
/// </summary>
/// <param name="pos"></param>
public void WorldToScreen(Vector3 pos)
{
//克隆物体
GameObject obj = Instantiate(Resources.Load("prefabs/Wts_Icon")) as GameObject;
//获取屏幕坐标
Vector3 pt = Camera.main.WorldToScreenPoint(Cube.transform.position);
//获取在(参数1)Canvas下(参数2)屏幕坐标对应(参数3)摄像机下的(参数3)Ui坐标
Vector2 v;
RectTransformUtility.ScreenPointToLocalPointInRectangle(m_canvas.transform as RectTransform, pt, m_cam, out v);
//给物体位置赋值并设置父物体
obj.transform.position = v;
obj.transform.SetParent(m_canvas.transform, false);
}
这种也是做血条跟随之类需求的实现方式之一。
最后点一下obj.transform.SetParent(m_canvas.transform, false);这个方法不能用obj.transform.SetParent(m_canvas.transform);代替,也不能随意改动执行顺序,也是坑之一。因为你生成的物体是在3D场景里,直接放在父物体下会发生位置和大小的变化,改动顺序也是一样。
以上。