与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; 
            
        //}
    }
    */
}

效果图

点击前

android unity3d交互 unity3d交互怎么做_unity3d


点击后

android unity3d交互 unity3d交互怎么做_System_02


这次没用动图,下次一定~

我用的版本为Unity2018.3.5