与3D物体交互
- 思路
第一步,我们想在Unity3D中交互的时候,首先我们想到的是射线,调用Ray这个API,这样我们就可以用我们的鼠标(键盘)来与3D物体交互了,在这个案例中我用的是鼠标与之交互,如果有兴趣的可以用键盘试一试,我在下一篇中将会使用键盘与之交互,并且制作类似于吃鸡或者APG游戏中拾取物体那样。
第二步,交互一般都是有UI或者是窗口,当触发一个事件时将UI弹出来。
第三步,制作UI。 - 步骤
private void MouseClickRay()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, 50, ClickCub.value))
{
WindosOfCube.Instance.ClickCubeisShow();
Debug.Log("被检测的物体的名字:" + hit.collider.gameObject.name);
}
}
我在TouchCube这个类中写了用鼠标控制射线的方法
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
这样就可以将射线与鼠标绑定;下面的ClickCub我定义的是LayerMask,通过给物体设 置不同的层级,也可以用Tag(标签),来区分要交互的物体。
然后,这里我遇到一个坑,我开始想的的在UpDate里面去使用它,然后控制它每次点击只会运行一次,但是在经历的多次尝试以后发现,我无法控制它,只能降低其频率,可能是我的方法不太对,我下来在试一试,如果成功我会在下一篇或者下下篇进行讲解,不过我找到了另一种方法,那就是OnMousexxx,这里有个小知识点
(Event和Input.GetMousexxx事件会被任何gameobject监控到,而OnMousexxx事件只会被该脚本附加上的gameobject监控到),Inpput.GetMousexxx要写在Update中,就会出现每帧调用的现象,而OnMousexxx只会在过载的gameobject中才可以,而且只运行一次。
接下来,就可以开始写UI的逻辑了,这个面板是不是在开始的时候应该隐藏起来,有很多种方法,比如,先将UI移出Canvas,需要的时候在移回来,或者直接让面板开始不可见,然后需要的时候在显示,这样他的位置就不需要移动,还有一种不太可取的方法就是,需要的时候实例化出来,用完就销毁,然后反复这个操作,各有个的特点,不过我用的是第二种方法,将其添加CanvasGroup组件,然后可以修改透明度值,就可以达到这种效果,怎么简单怎么来。
需要隐藏的时候:
canvasGroupWindos.GetComponent<CanvasGroup>().alpha = 0;
canvasGroupWindos.GetComponent<CanvasGroup>().interactable = false;
canvasGroupWindos.GetComponent<CanvasGroup>().blocksRaycasts = false;
需要显示的时候:
canvasGroupWindos.GetComponent<CanvasGroup>().alpha = 1;
canvasGroupWindos.GetComponent<CanvasGroup>().interactable = true;
canvasGroupWindos.GetComponent<CanvasGroup>().blocksRaycasts = true;
我将另外两个脚本写成单例,调用的时候就比较简单了,写按钮的时候我用了拉姆达表达式,匿名委托来表示回调,也是比较的简单,(写代码,简单明了实现功能就可以了,不需要搞得太复杂)这样一个与3D物体的交互就完成了。
以下是源代码和脚本的名字
ClickManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ClickManager : MonoBehaviour
{
public Button CloseBtn;
private void Start()
{
//lambda(拉姆达)匿名委托
CloseBtn.onClick.AddListener(()=> {
WindosOfCube.Instance.ButtonWindosClose();
});
}
}
WindosOfCube.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class WindosOfCube : MonoBehaviour
{
//单例,方便其他脚本调用
public static WindosOfCube Instance;
private void Awake()
{
Instance = this;
}
public CanvasGroup canvasGroupWindos;
//设置一个布尔条件保护
bool isShow;
void Start()
{
isShow = true;
if (isShow)
{
//开始先将窗口UI隐藏起来
canvasGroupWindos.GetComponent<CanvasGroup>().alpha = 0;
canvasGroupWindos.GetComponent<CanvasGroup>().interactable = false;
canvasGroupWindos.GetComponent<CanvasGroup>().blocksRaycasts = false;
}
}
public void ClickCubeisShow()
{
//当isShow为true时将UI显示出来
if (isShow)
{
canvasGroupWindos.GetComponent<CanvasGroup>().alpha = 1;
canvasGroupWindos.GetComponent<CanvasGroup>().interactable = true;
canvasGroupWindos.GetComponent<CanvasGroup>().blocksRaycasts = true;
}
}
public void ButtonWindosClose()
{
if (isShow)
{
canvasGroupWindos.GetComponent<CanvasGroup>().alpha = 0;
canvasGroupWindos.GetComponent<CanvasGroup>().interactable = false;
canvasGroupWindos.GetComponent<CanvasGroup>().blocksRaycasts = false;
}
}
}
TouchCube.cs
using UnityEngine;
public class TouchCube : MonoBehaviour
{
RaycastHit hit;
public LayerMask ClickCub;
private void MouseClickRay()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, 50, ClickCub.value))
{
WindosOfCube.Instance.ClickCubeisShow();
Debug.Log("被检测的物体的名字:" + hit.collider.gameObject.name);
}
}
private void OnMouseDown()
{
MouseClickRay();
}
/*这个是我之前的错误方法,代码写错了,可以注释掉
知道整个完成了以后就可以删掉,这样有助于思路的扩展,也会减少代码的书写
private bool isState = true;
void Update()
{
//if (isState)
//{
//Debug.Log("come 2222");
if (isState && Input.GetKey(KeyCode.Mouse0))
{
Debug.Log("come 333");
isState = false;
}
isState = true;
//}
}
*/
}
效果图
点击前
点击后
这次没用动图,下次一定~
我用的版本为Unity2018.3.5