赞
踩
昨天改《降龙十八掌》项目反馈时经理要求我在项目中点击到手印时显示爆炸特效,昨天折腾了好一会没弄好就先弄其它项目反馈了,今天改完反馈后有时间来研究下这个功能。
昨天就简单的写了点代码进行测试,加了一个Image和一个Sphere,目的是想在Scene场景中拖动Image移动时,在Game场景中能看到黑色的球Sphere能跟白色的Image在同一位置,如图所示:
这是白色Image的Anchor
其中ImageObj就是白色的Image,SphereObj就是黑色的球。
我项目分辨率为1920*1080, 经过测试,屏幕坐标没问题,一开始Image在屏幕中心位置时打印出(960,540),不过移动Image时世界坐标worldPos一直没有变化,一直等于相机的世界坐标,这就让我无语了,所以昨天先不管这个了,改其它反馈去了。
今天我决定先从原理着手,于是去网上找了下资料。有篇博客里有段文字讲了一下道理让我明白了。首先,摄像机对游戏世界的渲染范围是一个平截头体,就是一个立体梯形,不理解就百度看unity的相机资料。
在屏幕上,某个像素点相对于屏幕矩形的位置,可以对应于游戏世界中的点相对于某个截面的位置,关键在于这个点在哪个截面上,也就是说,关键在于这个截面离摄像机有多远!
在ScreenToWorldPoint这个方法中,参数是一个三维坐标,而实际上,屏幕坐标只能是二维坐标。参数中的z坐标的作用就是:用来表示上述平面离摄像机的距离。
也就是说,给定一个坐标(X,Y,Z),
首先截取一个垂直于摄像机Z轴的,距离为Z的平面P,这样不管X,Y怎么变化,返回的点都只能在这个平面上;
然后,X,Y表示像素坐标,根据(X,Y)相对于屏幕的位置,得到游戏世界中的点相对于截面P的位置,我们也就将屏幕坐标转换为了世界坐标。
总之,我们需要给屏幕坐标的z坐标先赋值再进行转换。
于是我添加了2行代码,如图:
- Camera uiCamera = GameObject.Find("UICamera").GetComponent<Camera>();//UI相机
- Vector3 ptScreen = RectTransformUtility.WorldToScreenPoint(uiCamera, ImageObj.transform.position);
- Debug.Log("ptScreen = " + ptScreen);
- ptScreen.z = 0;
- ptScreen.z = Mathf.Abs(Camera.main.transform.position.z - SphereObj.transform.position.z);
- Vector3 worldPos = Camera.main.ScreenToWorldPoint(ptScreen);
- Debug.Log("worldPos = " + worldPos);
- SphereObj.transform.position = worldPos;
经过测试后显示正常,随便Image处于什么位置,Game视图中球跟Image是在一块的。
最后只要把那段代码自己写进一个函数里适当改一下就能在项目中使用了。
- /// <summary>
- /// 获取让目标物体跟UI物体看起来在一起的世界坐标
- /// </summary>
- /// <param name="uiObj">UI物体</param>
- /// <param name="targetObj">目标物体</param>
- /// <returns></returns>
- public Vector3 GetUIToWordPos(GameObject uiObj, GameObject targetObj)
- {
- Camera uiCamera = GameObject.Find("UICamera").GetComponent<Camera>();//UI相机
- Vector3 ptScreen = RectTransformUtility.WorldToScreenPoint(uiCamera, uiObj.transform.position);
- Debug.Log("ptScreen = " + ptScreen);
- ptScreen.z = 0;
- ptScreen.z = Mathf.Abs(Camera.main.transform.position.z - targetObj.transform.position.z);
- Vector3 ptWorld = Camera.main.ScreenToWorldPoint(ptScreen);
- return ptWorld;
- }
- void ShowClickEffect()
- {
- GameObject obj = Instantiate(m_BoomPrefab, new Vector3(0, 0, 1), m_BoomPrefab.transform.rotation);
- Vector3 pos = GetUIToWordPos(HandObj, obj);
- obj.transform.position = pos;
- Destroy(obj, 0.5f);
- }
Instantiate()函数中产生的位置你可以自己定,我相机的位置x坐标是0,如果爆炸粒子大了你就把产生位置调远点或者把粒子调小点。
这是最后成功的效果截图。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。