本人unity 小白,最近在做毕业设计,需要拖动实验台上面的电学器件,经过不断查找发现只有沿着坐标轴的视角的代码,这就让我这种想做3D视角的很难受,于是研究了一番。
摄像机的视野可以看成以摄像机为顶点的金字塔形状,再加上视角并不是沿着轴向,那么想让物体沿着不与金字塔底面平行的平面移动就不能使用下面这种方法:Camera.main.ScreenToWorldPoint (Input.mousePosition.x , Input.mousePosition.y , z);
这段代码意思是获取鼠标在屏幕中的坐标并转换为世界坐标,其中z为得到的世界坐标与摄像机的距离,相当于将摄像机当作原点,面对方向为z轴得到的坐标。通过这种方法,鼠标离摄像机的距离要不不变,要不需要进行复杂的计算。
最后我的解决办法就是通过射线检测。
Camera.main.ScreenPointToRay(Input.mousePosition);这个代码可以发射一条从摄像机到鼠标的射线,也就是说上面提到的z从一个定值或者变量变为了(0-∞)这样一个范围,接下来只需要检测物体以及平面在哪就行了。
首先初始化
private Ray ra; //定义射线
private RaycastHit hit; //碰撞点
private Vector3 offset; //偏移
public bool is_element = false; //判断是否为element
public GameObject Element; //将碰撞获取的物体赋值给Element变量
private LayerMask mask = 1 << 8; //检测某层级
然后是按下鼠标,检测按到物体没有,并设置偏移。
if (Input.GetMouseButtonDown(0))//当鼠标左键按下后
{
ra = Camera.main.ScreenPointToRay(Input.mousePosition);//发射射线
if (Physics.Raycast(ra, out hit) && hit.collider.tag == "element")//检测碰撞并判断是否是element
{
is_element = true;
Element = hit.collider.gameObject;
if (Physics.Raycast(ra, out hit, 100, mask))//检测是否能够穿过其他层碰到所选层(要跟随移动的平面)
offset = Element.transform.position - new Vector3(hit.point.x, Element.transform.position.y, hit.point.z);//偏移
}
else
{ is_element = false; }
}
最后是物体跟着移动。
if (Input.GetMouseButton(0) && is_element == true)//如果按住鼠标左键不放且按下时按到了element
{
ra = Camera.main.ScreenPointToRay(Input.mousePosition);//每帧重新射线,保证线跟着鼠标
if (Physics.Raycast(ra, out hit, 100,mask ))
{
Element.transform.position = new Vector3(hit.point.x, Element.transform.position.y, hit.point.z) + offset;
}
}
放个总代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class drag : MonoBehaviour
{
private Ray ra;
private RaycastHit hit;
private Vector3 offset;
public bool is_element = false;
public GameObject Element;
private LayerMask mask = 1 << 8;
// Start is called before the first frame update
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))//当鼠标左键按下后
{
ra = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ra, out hit) && hit.collider.tag == "element")
{
is_element = true;
Element = hit.collider.gameObject;
if (Physics.Raycast(ra, out hit, 100, mask))
offset = Element.transform.position - new Vector3(hit.point.x, Element.transform.position.y, hit.point.z);
Debug.DrawLine(ra.origin, hit.point, Color.blue,10);
}
else
{ is_element = false; }
}
if (Input.GetMouseButton(0) && is_element == true)
{
ra = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ra, out hit, 100,mask ))
{
Element.transform.position = new Vector3(hit.point.x, Element.transform.position.y, hit.point.z) + offset;
}
Debug.DrawLine(ra.origin,hit.point, Color.red);
}
}
}
需要注意几点,我的物体只需要沿着桌面(水平面)运动,完全沿着平面运动可能会导致穿模等现象,需要调中心点等,所以最后的物体y变量就让他和原来一样了,若平面不水平,请自行更换。Debug是写代码时调试用的,可以删掉。
代码可以附在任意物体上,我放在了摄像机里面。
需要跟随移动的平面一定要改层级,我这里是改为了第八层。
跟随移动的物体要给标签,我给的element,可以自行更改标签及代码。
最后一点:平面和物体一定要给碰撞体(collider)!!!