與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