Unity3D 射線指定層獲取GameObject 注意 LayerMask



這一篇是純技術討論,看過我前面文章的童鞋應該清楚,我的奔跑是靠鼠標響應的,鼠標點到哪就跑到哪,后來又有了界面,麻煩就來了,我的界面居然能點 穿。我不希望點界面的時候還能點到界面后面的地面上,角色傻不拉幾的往那跑,那腫么辦呢,總不能每次點擊都要推斷點擊的物體名稱吧。那界面多了會累死的, 好在我們有標簽和層這兩個神器,所以我這里介紹兩種方案,都能達到效果。


方案一:利用標簽(Tag)攔截射線消息。

每一個GameObject的Inspector面板最上方都有個Tag選項,也就是說我們能夠給全部的物體加個標簽,Unity3d已經默認有了幾 個標簽,這里我們能夠自己定義個UI的標簽。然后把全部UI都用這個標簽。點擊Tag右方的選項。選Add Tag。Size調成2。Element 0的值改成UI。


然后你全部不想被點穿的UI都選成這個標簽。

除了設置標簽,另一點非常重要,就是界面要加碰撞器Collider,有的UI默認就有碰撞器,比方NGUI的button,你能夠看到有一個Box Collider。假設沒有的你就要自己加了,Size那里要調成這個UI的尺寸:


這樣UI才干接收射線碰撞。然后代碼能夠這樣寫:

[csharp]  view plain copy
  1. Ray ray1 nguiCamera.camera.ScreenPointToRay(Input.mousePosition);  
  2. RaycastHit hit1;  
  3. if (Physics.Raycast(ray1, out hit1))  
  4.     if (hit1.collider.gameObject.tag == "UI" 
  5.         return 
  6.  

上面的nguiCamera是獲取的NGUI下的Camera。由於是這個Camera發出的射線與UI的碰撞,而不是Main Camera,這點要注意。其它的不解釋了。非常easy,自己看。


方案二、利用層(Layer)攔截射線消息

每一個GameObject的Inspector面板最上方都也有個Layer選項,就在Tag旁邊,unity3d已經有了幾個層。我們新建個層。 也叫UI,點擊Add Layer,能夠看到從Layer0到Layer7都灰掉了,那是不能用的,從第八個起能夠用。所以在第八個建個UI的層。


然后我們看一下Physics的Raycast的參數:

static function Raycast (ray Rayout hitInfo RaycastHitdistance : float = Mathf.InfinitylayerMask : int = kDefaultRaycastLayers) : bool

普通情況下我們僅僅用前兩個參數,distance表示射線距離,默認是無限遠,重點是最后一個參數layerMask,專門處理layer過濾的,是個整型,怎么用呢。是靠layer的二進制位來操作的。看以下代碼就清楚了:

[csharp]  view plain copy
  1. Ray ray1 nguiCamera.camera.ScreenPointToRay(Input.mousePosition);  
  2. RaycastHit hit1;  
  3. LayerMask mask << LayerMask.NameToLayer("UI");  
  4. if (Physics.Raycast(ray1, out hit1, 600, mask.value))  
  5.     return 
  6.  

LayerMask的NameToLayer是通過層的名稱返回該層的索引,這里是8,然后1<<8換算成LayerMask值,再用LayerMask的value就能夠了。

注意也必須設置collider才干接收碰撞,這里才干推斷到。

我這里提供了兩個方案,假設有其它方案的歡迎留言,謝謝。

筆者補充內容
 假設是在代碼中自己創建GameObject指定Layer的方法和獲取Layer進行射線的注意地方。
例如以下創建一個GameObject:

          GameObject _newObj = new GameObject();
            _newObj.layer = LayerMask.NameToLayer("CommObj"); //指定Layer
            _newObj.name = "Terrain0_Grass";

            print(LayerMask.NameToLayer("CommObj"));

            BoxCollider _collider = _newObj.GetComponent();
            _collider = _collider == null ?

_newObj.AddComponent() : _collider;
            _collider.center = Vector3.zero;
            _collider.size = new Vector3(10f, CommonDef.Layer0_Terrain_Grass, 10f);

            MeshFilter _meshFilter = _newObj.GetComponent();
            _meshFilter = _meshFilter == null ?

_newObj.AddComponent() : _meshFilter;

            Mesh _mesh = ModelResManager.AddTerrainGrassMesh(10, 10);
            _meshFilter.mesh = _mesh;

            MeshRenderer _meshRender = _newObj.GetComponent();
            _meshRender = _meshRender == null ? _newObj.AddComponent() : _meshRender;

            //指向父子節點關系,僅僅需指定其位置組件父子關系;
            GameObject _subObj = GameObject.CreatePrimitive(PrimitiveType.Cube);
            _subObj.transform.parent = _newObj.transform;

以上是創建一個GameObject。賦上Collider組件用於射線碰撞檢測。下面是獲取指定Layer射線的方法:
 
          LayerMask mask = 1 << LayerMask.NameToLayer("CommObj");

          Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
          RaycastHit _hitInfo;
          if (Physics.Raycast(ray, out _hitInfo, 1000f, mask.value))
          {
             m_currSelectObj = _hitInfo.collider.gameObject;
             m_mouseMovePos = _hitInfo.point;
         }

黑體字為獲取指定Layer的mask值。用於射線檢測。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM