iT邦幫忙

2022 iThome 鐵人賽

DAY 6
0
自我挑戰組

Unity 基本功能實作與日常紀錄系列 第 6

Day6: Combination with RaycastHit and Line Renderer

  • 分享至 

  • xImage
  •  

最近因為實驗室事情比較多,跟芬蘭那邊的實驗室有些共同的計畫要處理。所以這邊我就先將前兩天所撰寫文章中的內容總結做個小小的練習XD,剛好做個回顧。
當然我們知道在選擇物件的時候會透過RaycastHit 來觀察是否觸發到所選物件,但我們或許也會希望有個明確的指示來讓我們知道到底選擇了哪樣物件,因此若能透過LineRenderer 就能顯示一條指示物件的線。例如我們在Oculus 透過Controller 選擇任一虛擬環境上的按鈕一樣,從Controller 會發出一條帶有顏色的射線讓User 知道自己選取的項目是甚麼,更好判讀當前的指向行為,接下來就針對該功能做個簡單的實驗。

建置場景

  1. 首先我們新增一個 Sphere,更改名稱為 Player 。並 Reset 該物件的 Transform 。 首先要了解Player前方為 Z軸,故我們在前面新增一個物件。任何樣式皆可。目前如下方圖片顯示。

  2. 接著我們調整該 Main Camera 的視角,調整到 Player 的後方我個人會將該 Main Camera 成為 Player 的子物件後接著再去調整該 Main Camera 的位置對應到Parent Player物件,使 Display 看起來的視角如下。注意到 Main Camera Transform 調整的 Position 的參數。

可以看到Player 的視角

  1. 接下來我們製作該 Player 手上的槍枝,首先新增一個 Cube,命名為 Gun 後放入到我們下面顯示檔案的地方,接下來該Gun 物件就會成為 Prefab。Prefab 就是之後你更改它的內容後,後續在環境中同樣是該Prefab 就會同時跟著一起改變。

  2. 接著點選下面的 Gun ,Scene 環境就會獨自follow 該物件,這是讓你可以單獨針對Prefab 物件做設定,我們就可以開始設計物件的樣式。

我大概設計成這樣,依照自己的喜好設計即可。

  1. 設計好後我們檔案資料中的物件 Prefab 也會跟著改變。之後就可以直接將該物件拉入Scene直接使用

  2. 接著就要將我們的 Gun 放進到我們的Main Camera中,成為該子物件。接著調整一下該Gun 的Transform後讓我們可以看到槍枝放在 Player 旁邊。

顯示Ray 透過滑鼠點選的物件

  1. 接下來進入到撰寫腳本的地方,先新增一個RaycastManagement.cs在 Player 中。

  2. 撰寫一個簡單功能,就是讓 Ray 能追蹤我的滑鼠的位置並且顯示目前Ray 射線射到的物件名稱。 可以先宣告需要的變數與物件比如 Ray 與 RaycastHit 就是使用射線需要的類別物件,Camera 就是該視角看出指向的位置,並將當前滑鼠指向的目標物設定到 Ray 上。最後再透過一個簡單的判斷來將其顯示當前射線上物件的名稱 hit.transform.name。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RaycastManagement : MonoBehaviour
{
   Ray ray;
   RaycastHit hit;
   Camera playerCamera;
   
   void Start() 
   {
     playerCamera = Camera.main;
   }

   void Update() {
      ray = playerCamera.ScreenPointToRay(Input.mousePosition);         // the ray will follow the mousePosition 
      
      if(Physics.Raycast(ray, out hit, 100))
      {
         print(hit.transform.name);
      }   
   }
}
  1. 實作後如下,會顯示滑鼠位置上也就是 Ray 射線觸發物件的名稱。

Ray 選擇的物件點選後消失

  1. 我們只需新增一個判斷滑鼠左鍵是否點選,以及讓物件消失的方法即可。如下:
void Update() {
      ray = playerCamera.ScreenPointToRay(Input.mousePosition);          

      if(Physics.Raycast(ray, out hit, 100))
      {
         //print(hit.transform.name);
         if(Input.GetMouseButtonDown(0))      // check the mouse left button click
         {
            Destroy(hit.transform.gameObject);   // disable to show the object by using transform.gameObject
         }
      }   
   }
  1. 接下來點擊場景的物件後,物件就會消失。

新增LineRenderer 加入指向射線

  1. 首先新增一個 LineRenderer 元素在我們的 Player上。 並請將我們 LineRenderer中的 Material 設定成 Default Line 。

  2. 開始撰寫程式碼。跟先前說明一樣首先我們要取得 LineRenderer 的物件。接著在一開始宣告Line 的物件後,設定該 endWidth, startWidth, positionCount 的參數。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RaycastManagement : MonoBehaviour
{
   LineRenderer lr;
   Ray ray;
   RaycastHit hit;
   Camera playerCamera;
   
   void Start() 
   {
     playerCamera = Camera.main;

     lr = GetComponent<LineRenderer>();
     if(lr == null)
      {
         lr = gameObject.AddComponent<LineRenderer>();
      }

      lr.endWidth = 0.05f;
      lr.startWidth  = 0.05f;
      lr.positionCount = 2;
   }

   void Update() {
      ray = playerCamera.ScreenPointToRay(Input.mousePosition);         // the ray will follow the mousePosition 

      if(Physics.Raycast(ray, out hit, 100))
      {
         //print(hit.transform.name);
         if(Input.GetMouseButtonDown(0))
         {
            Destroy(hit.transform.gameObject);
         }
      }   
   }
}
  1. 最後就是要將我們的Gun 能連出一條線出來到我們滑鼠點擊的位置。 首先宣告Gun 的 Transform 目的是之後要知道其 Position。這邊也會去控制該Line 再點選到物件的時候才會顯示,若沒有點選到任何物件則不會顯示該 Line。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RaycastManagement : MonoBehaviour
{
   public Transform Gun;
   LineRenderer lr;
   Ray ray;
   RaycastHit hit;
   Camera playerCamera;
   
   void Start() 
   {
     playerCamera = Camera.main;

     lr = GetComponent<LineRenderer>();
     if(lr == null)
      {
         lr = gameObject.AddComponent<LineRenderer>();
      }

      lr.endWidth = 0.05f;
      lr.startWidth  = 0.05f;
      lr.positionCount = 2;
   }

   void Update() {
      ray = playerCamera.ScreenPointToRay(Input.mousePosition);         // the ray will follow the mousePosition 

      if(Physics.Raycast(ray, out hit, 100))
      {
         lr.enabled = true;  // if hit object then show the line
         lr.SetPosition(0, Gun.position);    // line start 
         lr.SetPosition(1, hit.point);       // line end
         print(hit.transform.name);
         if(Input.GetMouseButtonDown(0))
         {
            Destroy(hit.transform.gameObject);
         }
      } else{
         lr.enabled = false;  // if not hit then disable to show the line
      }
   }
}
  1. 回到 Unity 後將我們的Gun 物件拉到我們的Scripts 中,接著執行看看會不會Line 會不會從Gun 射向我們Mouse 所點選的位置上。

  2. 結果會呈現如下的樣子。第一張是若有瞄準到物件時(Line顯示),下一張是沒有瞄準到物件的樣子(Line 消失)。

  3. 最後可以調整一下 Line 的顏色,我們直接到 LineRenderer 底下去調整。

  4. 最後Line就會呈現很漂亮的模樣XDD,這樣就覺得自己是漸層藝術大師。

Gun 隨著瞄準到的方向移動

  1. 首先新增一個 Target Point Object。注意要將該 Box Collider 給取消勾選避免Raycast 偵測到Collider 變數誤判。


  2. 接著回到文本中改寫一下我們的程式碼。這邊有個很重要的地方是若要使用 SetActive( ) 的話就必須要使用 GameObject 來宣告其物件。故這邊TargetPoint 為GameObject型態。若我們瞄準到任何物件後,我們就將槍枝瞄準到該 TargetPoint 上。這裡我使用 LookAt( ) 這個內建的函數簡單就能實現槍枝朝向目標點的效果。瞄準點的設計之前有提過這邊就不深入說明。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RaycastManagement : MonoBehaviour
{
   public Transform Gun;
   public GameObject TargetPoint;  // add the target point GameObject
   LineRenderer lr;
   Ray ray;
   RaycastHit hit;
   Camera playerCamera;
   
   void Start() 
   {
	   TargetPoint.SetActive(false);  // when started then disable to show
     playerCamera = Camera.main;

     lr = GetComponent<LineRenderer>();
     if(lr == null)
      {
         lr = gameObject.AddComponent<LineRenderer>();
      }

      lr.endWidth = 0.05f;
      lr.startWidth  = 0.05f;
      lr.positionCount = 2;

   }

   void Update() {
      
      ray = playerCamera.ScreenPointToRay(Input.mousePosition);         // the ray will follow the mousePosition 
      if(Physics.Raycast(ray, out hit, 100))
      {
         TargetPoint.SetActive(true);
         TargetPoint.transform.position = hit.point;   // hit.point set to the target point
         GunLookAt();
         lr.enabled = true;
         lr.SetPosition(0, Gun.position);
         lr.SetPosition(1, hit.point);
         //print(hit.transform.name);
         if(Input.GetMouseButtonDown(0))
         {
            Destroy(hit.transform.gameObject);
         }
      } else{
         TargetPoint.SetActive(false);
         lr.enabled = false;
         GunLookAt();
      }
      
   }


   void GunLookAt() 
   {
      Gun.LookAt(TargetPoint.transform);   /// gun look at the target point 
   }
}
  1. 最後的結果如下,槍枝會隨著 Target Point 瞄準到物件時跟著轉向到該目標。這樣就會像是瞄準該物件一樣。

結論

  1. 首先我們今天結合 RaycastHit, LineRenderer 實現物件指向並有射線的功能。
  2. 透過 ray = playerCamera.ScreenPointToRay(Input.mousePosition); 我們可以明確的知道滑鼠游標在畫面的位置,對應到該 Ray 的方向(這邊目的是要對應到 HMD 的視角方向)。
  3. LookAt(Transform) 是個很好使用到追蹤或是持續觀看某角度上的物件的方法。

參加IT鐵人賽後我發現養成了一個好習慣, "早睡早起",早上睡早上起 : )


上一篇
Day5: Understand Line Renderer
下一篇
Day7: Understand Animation Curve
系列文
Unity 基本功能實作與日常紀錄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言