Unityでインディゲームを作る!

Unityでのゲーム制作を目指し、それに関わる話題についてのブログ

物理演算、衝突判定、コライダーの検出などで使うLayerMaskについて [Raycast, Collider, Culling-Mask]

 Layer(レイヤー)とは、ゲーム・オブジェクトを分類したり、あるいは物理演算や衝突判定において、各レイヤー間でぶつかるかどうかを設定したりするのに使える、Unityの基本システムの一つです。

 ビルトイン(組み込み)・レイヤーとして、DefaultやTransparentFXなどが用意されてますが、自分で独自にレイヤーを作ることも出来るし、Project Settings > Physicsページで各レイヤーの当たり判定を設定することも出来ます。

 

 LayerMask(レイヤーマスク)とは、このLayerの組み合わせを表現するデータタイプですが、Layerとは性質が異なるものなので注意が必要。先に言ってしまえば、最大32個となる全てのレイヤーの有効無効の状態を一つのデータとしてまとめて保存しておけるのがLayerMaskです。

 

 Raycast, SphereCastCheckSphereなどのメソッドで衝突判定やコライダー検出をする際にLayerMaskを使うことで、対象非対象となるレイヤーを設定して、狙いたいオブジェクトと取り除きたいオブジェクトを分けることが出来ます。

 またカメラのCullingMaskでレイヤーを使ってレンダリングするかしないかの設定も行っているので、そう考えるとレイヤー及びレイヤーマスクはかなり重要な機能です。

 

 自分もLayerMaskの落とし穴にハマってしまい、幾分かの時間を浪費してしまったので、ここで要点をまとめておこうと思います。

 

Layerは整数!LayerMaskも整数?

LayerMask_Layers

 Layerにはそれぞれ整数が割り振られています。通常、シーンに追加されるゲームオブジェクトにはDefaultが設定されていますが、Defaultには0番が割り振られています。

そのゲームオブジェクトのレイヤーには

player.gameObject.layer

でアクセスすることが出来て、それをコンソールに表示すれば、この場合当然0が表示されるわけです。

 じゃあLayerMaskをDefaultに設定してコンソールに表示するとどうなるか、という疑問が生じます。

 

LayerMask_Inspector

 LayerMaskをスクリプト上で扱う場合、publicで宣言するか、[SerializeField]属性を付けてprivateで宣言すると、インスペクターに表示されてドロップメニューにてレイヤーの複数選択が可能になるので、この方法が便利です。

 

 今回の実験のためにLayerMaskTestというスクリプトを作成し、いろいろ確かめてみました。

LayerMask_Script

 このスクリプトが取り付けられたゲームオブジェクトのレイヤーはDefaultで、インスペクター上のLayerMaskもDefaultが選択されています。ここで、Debug.Logメソッドを使い、それぞれの整数値をコンソールに表示してみましょう。

 LayerMaskの数値はlayerMask.valueという風にvalueプロパティからアクセスできます。

 

LayerMask_Default

 なんと0と1とそれぞれ異なる値が表示されてしまいました。0と1となると、コンピュータ上においては『はい』と『いいえ』くらい意味が違うものであり、これは衝撃的です。実はLayerMaskで扱われる整数は整数として解釈はされていません。

 

0と1のチェックボックス

 実はLayerMaskは整数値ではあるのですが二進数として考えられており、その二進数を単純な数字としてではなく、bool値の列、つまりビット列として扱うことで各レイヤーの有効無効を表現しています。

LayerMask_LayersAndBitArray

 二進数といえば1101のように0と1の列で数字を表現しますが、この場合、チェックボックスが並んでいて0は未チェック(false)、1はチェック済み(true)、というような捉え方をするのが分かりやすいと思います。1となっているレイヤーが有効、という感じです。二進数の各桁がそれぞれ各レイヤーに対応している、ということになります。

 

 各レイヤーにはそれぞれ整数が割り振られていますが、この数字は二進数において各桁は2のN乗である、のNに対応しているのです。よって、2の0乗は1なので、先ほどの例でlayerMask.valueは1、となったのでした。

00000001

 これはDefaultが選択されていますよ、というのを二進数の1桁目(2の0乗桁)を1にすることで表現している、ということになります。

 

LayerMask_UI

 LayerMaskをUIに設定し、表示させると"32"です。通し番号は5ですから、これは相当かけ離れた数字ですが、2の5乗は32であり、二進数では100000となるのでこれで正解です。

 

 こうした二進数を使った一つの数字で有効無効を表現する方法は、複数の状態の表現、保存を可能にします。

LayerMask_MultSelection

 ここでTransparentFxレイヤーとPlayerレイヤーをLayerMaskに設定します。TransparentFXは1番、Playerは3番なので、2**1 + 2**3 = 10となります。

二進数では四桁目と二桁目を1とするので、1010となります。

LayerMask_TransparentFX&Player

またLayerMaskの選択メニューにはEverythingがありますが、これを選択すると…

LayerMask_EveryThing

とんでもない数になっちゃってますが、これも単に二進数(32bit)の全ての桁を1にしたから、という理解をすればいいだけです。

 

  選択したレイヤーの通し番号+ 1の桁を1とする、というシンプルで理にかなった方法でレイヤー真偽表(真理値表)を作成するのがLayerMaskということになります。

 これに基づいて、Raycastメソッドなどにおいて、チェックが入れられたレイヤーを目標に検出処理がなされる、ということです。

 

まとめ

 というわけで、LayerMaskについてまとめてみました。単純にゲーム・オブジェクトのグループ分けにも使えるし、当たり判定関連においても活用すべき大事な機能だなと改めて考えさせられました。

 余計な物理演算をしない、狙ったレイヤーのコライダーを検出する、というような処理をする上で、しっかり押さえておくべき機能だと思うので、さらに詰めていきたいです!