Unity3D在2D游戏中获取触屏物体的方法
我们的需求是:
假如屏幕中一个棋盘,每个棋子是button构成的,我们希望手指或者鼠标在哪里,就显示那个位置的button信息。
网上有很多获取触屏物体信息的信息的方法如下面代码所示:
Camera cam = Camera.main; // pre-defined
...
if (touch.phase == TouchPhase.Bagan)){ // 如果触控点状态为按下
Ray ray = cam.ScreenPointToRay(Input.position);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
Debug.Log(hit.transform.name); // 输出点击物体名称
startTouchPos = touch.position;
}
}
但是在实际测试时,发现可以进入到if (touch.phase == TouchPhase.Bagan))这个分支中,但是Physics.Raycast(ray, out hit)始终返回false。
错误1:Physics.Raycast方法只适用于3D场景
翻阅资料发现:Physics.Raycast方法适用于3D场景下,在2D场景下是不会起作用的。
于是我们找到了2D场景下的替代方法:Physics2D.Raycast()
该方法最简单的定义如下:
public static RaycastHit2D Raycast(Vector2 origin, Vector2 direction)
需要传入两个参数:origin是射线发射的起始位置,direction是射线的方向。
为了测试效果,我们制作了demo如下:
RayHandler对象对应的脚本RayHandler.cs如下:
public class RayHandler : MonoBehaviour
{
// Start is called before the first frame update
private Camera _camera;
void Start()
{
_camera = Camera.main;
}
// Update is called once per frame
void Update()
{
Vector2 direction = Input.mousePosition - Camera.main.transform.position;
RaycastHit2D hit = Physics2D.Raycast(Camera.main.transform.position, direction);
Debug.DrawRay(Camera.main.transform.position, direction, Color.red, 30f);
if (hit.collider != null)
{
Debug.Log("true");
}
}
}
加入Debug.DrawRay(Camera.main.transform.position, direction, Color.red, 30f);是为了更方便地观察到射线的情况。
我们发现射线(红色线段)穿透button的次数大大多于true日志的次数。
这个方案还有个缺陷:如果从一个点发出射线,当出发点和终点之间有其他物体时,射线检测到的是另一个物体,而不是当前鼠标(触屏点)对应的物体。
错误2:普通UI如Image、Button等一般用射线是不起作用的。
EventSystem.current.RaycastAll()可以将当前屏幕上的所有可检测的物体全部检测到,该方法需要自己构造一个PointerEventData参数传入检测的点坐标。
参考代码如下:
void Update()
{
PointerEventData pointerData = new PointerEventData(EventSystem.current);
pointerData.position = Input.mousePosition;
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointerData, results);
if (results.Count > 0) {
foreach (RaycastResult r in results) {
if (r.gameObject.layer == LayerMask.NameToLayer("button")) {
Debug.Log(r.gameObject.name);
}
}
}
}
针对Button1和Button2添加了button的layer,这样就可以过滤出我们想要的物体。
另外我做了测试,创建了Empty、2D Object,使用Physics2D.RaycastAll也没有生效。
测试的代码如下:
void Update()
{
Vector3 pos = GetTouchPosition();
Ray myRay = Camera.main.ScreenPointToRay(pos);
RaycastHit2D[] hits = Physics2D.RaycastAll(new Vector2(myRay.origin.x, myRay.origin.y), Vector2.zero);
if(hits.Length > 0)
{
Debug.Log("true");
}
}
public static Vector3 GetTouchPosition()
{
return Input.mousePosition;
}
可能Physics2D.RaycastAll适用于一个游戏Player向另一个物体发射射线,而不是从触屏点发射射线。反正从触屏点通过Physics.Raycast类函数发射射线我始终没有成功过!!!!