ひとりでのアプリ開発 - fineの備忘録 -

ひとりでアプリ開発をするなかで起こったことや学んだことを書き溜めていきます

Unity - Layer、LayerMask:レイヤーに関する操作まとめ

初めに

 レイヤーの変更や追加の方法、GameObject.layer や LayerMask などスクリプトからレイヤーを扱う方法をまとめます。

レイヤー

レイヤーとは

 レイヤーを使うことで、カメラが描画するレイヤーやレイキャストに使用するレイヤーを選択することができます。

docs.unity3d.com

 各レイヤーには0から31までの 32個の整数によって、レイヤー番号が割り当てられています。


レイヤーの変更・追加

 オブジェクトの Inspector からレイヤーを変更できます。

 Add Layer... をクリックすると、Inspector に Tag & Layers(下の画像のような画面)が表示され、レイヤーを追加することができます。


Culling Mask を使って、カメラに描画するレイヤーを選択する

 Camera の Rendering > Culling Mask からカメラに描画するレイヤーを選択することができます。チェックが入っているレイヤーは描画され、チェックが入っていないレイヤーは描画されません。


GameObject.layer

 GameObject.layer からレイヤーを取得、変更することができます。返り値は int であり、割り当てられているレイヤー番号が返ってきます。

//public int layer ;

//割り当てられている整数を代入
//Defaultレイヤーに0が割り当てられているときは, 下のようにすればDefaultに変更可能
gameObject.layer = 0;

※通常は、整数を直接代入せず、LayerMask.NameToLayer を使い、レイヤー名を整数に変換したものを代入します。(後述)

docs.unity3d.com

LayerMask

 LayerMask は Physics.Raycastで使用するレイヤーを指定します。LayerMask を使うことで、Ray と衝突判定を行うレイヤーを選択することができます。また、複数のレイヤーが含まれるレイヤーマスクを作ることもできます。

docs.unity3d.com

LayerMask.value

 LayerMask.value は、レイヤーマスクを整数に変換した値です。注意点は各レイヤーに割り当てられたレイヤー番号ではないということです。

(レイヤー番号が i, j, k のレイヤーが含まれたレイヤーマスクの値)
2^i + 2^j + 2^k

Inspector からレイヤーマスクを取得する

 LayerMask を public で定義することで、Inspector からそのレイヤーマスクに含むレイヤーを選択できます。下の画像のように複数選ぶことも可能です。

public LayerMask obstacleLayerMask;  //InspectorからLayerMaskを選択できるようにしている


LayerMask.GetMask:スクリプトからレイヤーマスクを取得する

 public にせず、スクリプトからこの LayerMask を取得する場合は、LayerMask.GetMask を使います。

//public static int GetMask (params string[] layerNames);

using UnityEngine;

public class Example : MonoBehaviour
{
    // レイヤー名を指定するための変数
    private string[] layerNames = { "Default", "TransparentFX", "Water" };  //レイヤーの名前を入力

    // レイヤーマスクを取得するための変数
    private LayerMask layerMask;

    private void Start()
    {
        // レイヤーマスクを取得]
        // Defalut:0, TransparentFX:1, Water:4 のとき, 2^0+2^1+2^4=19が返ってくる
        layerMask = LayerMask.GetMask(layerNames);
    }
}
Physics.Raycast

 Raycast については、下の記事で説明しております。Physics.Raycast についても書いておりますので、そちらをご覧ください。

fineworks-fine.hatenablog.com

LayerMask と Physics.Raycast を使って衝突を判定する

 Physics.Raycast の引数に LayerMask を入れることでどのレイヤーについて判定したいのか、選択することができます。

(例)

using UnityEngine;

public class LayerTest : MonoBehaviour
{
    public float moveSpeed;
    public LayerMask obstacleLayerMask;  //InspectorからLayerMaskを選択できるようにしている
    private void Update()
    {
        float horizontalInput = Input.GetAxis("Horizontal");
        float verticalInput = Input.GetAxis("Vertical");

        Vector3 movement = new Vector3(horizontalInput, verticalInput, 0f);
        Vector3 targetPosition = transform.position + movement * moveSpeed * Time.deltaTime;

        RaycastHit hit;
        if (Physics.Raycast(transform.position, targetPosition - transform.position, out hit, movement.magnitude * moveSpeed * Time.deltaTime, obstacleLayerMask))  //obstacleLayerMaskで選択したレイヤーとの衝突を検知
        {
            // 障害物との交点から移動可能な方向を計算する
            Vector3 moveDirection = Vector3.ProjectOnPlane(movement, hit.normal).normalized;
            targetPosition = transform.position + moveDirection * moveSpeed * Time.deltaTime;
        }

        transform.position = targetPosition;
    }
}

youtu.be

LayerMask.LayerToName、LayerMask.NameToLayer

 LayerToName は整数をレイヤー名に、NameToLayer はレイヤー名を整数に変換する関数です。

(LayerToName)

//public static string LayerToName (int layer);

using UnityEngine;

public class Example : MonoBehaviour
{
    void Start()
    {
        // Prints the name of the layer 1

        Debug.Log(LayerMask.LayerToName(1));  //デフォルトでは、1が割り当てられているTransparentFXが返ってくる
    }
}

(NameToLayer)

//public static int NameToLayer (string layerName);

using UnityEngine;

public class Example : MonoBehaviour
{
    void Start()
    {
        Debug.Log(LayerMask.NameToLayer("TransparentFX"));  //デフォルトでは、TransparentFXが割り当てられている1が返ってくる
    }
}

※NameToLayerの引数にレイヤー名以外を入力すると、-1が返ってきます。

レイヤーを全取得する

 下のスクリプトを使うことで、レイヤーを全取得することができます。

 各レイヤーに0から31までの整数が割り当てられていることと LayerMask.LayerToName を使っています。

/// <summary>
/// Layer名をキー、Layer番号を値とするDictionaryを返します。
/// </summary>
public static Dictionary<string, int> GetAllLayers()
{
    Dictionary<string, int> layers = new Dictionary<string, int>();
    for (int i = 0; i < 32; i++)
    {
        string layerName = LayerMask.LayerToName(i);
        if (!string.IsNullOrEmpty(layerName))
        {
            layers.Add(layerName, i);
        }
    }
    return layers;
}

最後に

  • レイヤーを使うことで、カメラが描画するレイヤーやレイキャストに使用するレイヤーを選択することができます。
  • スクリプトから扱うときは、LayerMask を使う