親子で結んだり共通のTagを持っているGameObjectは簡単にScene中から探し出せますが、Layerに属するGameObjectを見つけてくるものが探しても無かったので、作ってみました。
#LayerMaskでGameObjectを探す
最初にScriptを出すと、こういう感じです。
public static GameObject[] FindGameObjectsWithLayerMask(LayerMask layerMask)
{
GameObject[] goArray = GameObject.FindObjectsOfType<GameObject>();
List<GameObject> goList = new List<GameObject>();
foreach (GameObject go in goArray) {
// LayerMask bit check
if (((1 << go.layer) & layerMask.value) != 0) {
goList.Add(go);
}
}
if (goList.Count == 0) {
return null;
}
return goList.ToArray();
}
探す方法の解説
1. とりあえず、Findで先ず、全てのGameObjectを拾ってきます
2. その中で、LayerがLayerMaskでビットが立っているかを確認します
3. 立っていたGameObjectをListに突っ込みます
4. 発見が出来なくてListが空ならnull
、発見が出来でListの要素があったら配列にして返します。
LayerMaskの解説
###GameObject.layer
はint型
単純な整数型になっていて、どのLayerか一つ、指定されます。エディタの画面を見ると、こういう感じです。
例えばこの例では、Player
を指定していると、gameObject.layer=13
になります。
LayerMask
はビット列
それに対して、LayerMask
は同じくint型なのですが、これの中で複数のLayerを指定できています。これはどういう仕組みなのかというと、
右から数えたビット数のところが1
のところが有効なLayer
という仕組みです。例えば、上記のCover=8
とGround=10
が有効な場合は以下のようになります。
15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
指定位置のビットが1
かをみる方法
この仕組みを理解すると、シフト演算と論理積で確認ができます。
if (((1 << go.layer) & layerMask.value) != 0)
の部分です。
-
1 << go.layer
で左シフトし、LayerMask
の位置に合わせます。 - その値と論理積をとり、指定位置が
1
の場合は同じ値、0
の場合は演算結果が0
になります。
補足
これが簡単と思って実装していますが、今のC#ならBitArray
を用いることも可能です。試してみた人はどうぞ!
やってない理由は、バイナリレベルで考えるとほぼ同じビット操作になるので、CPUリソースで差が無さそうと思ったからです。まあ、やってないので気になる方はどうぞw