ブルーノのC#プログラミング & unity勉強日記

プログラミング素人、ブルーノの自主勉強ノートです。他のプログラミングを勉強したい方の助けになれば幸いです。その他趣味の雑記もしていきたいです

【Unity】Physics.Raycastの引数"LayerMask"の注意

f:id:covory10101101276:20200507192306j:plain
ベルギー -ブリュッセル-

みなさんこんにちは🌞


マイナンバーカードで10万円給付申請をしようと思ったのにいつの間にかカードを無くしていて激込みの役所にまた行かなくてはならなくなってしまったブルーノです。めんどくさいけどいかなきゃ。。。


さて、今回はRayを使った様々なオブジェクトの探索についてこんがらがったので、まとめました。

Rayを使ってオブジェクトを探索するとき、Physics.Raycast()もしくはPhysics2D.Raycast()を使いますよね。
docs.unity3d.com
docs.unity3d.com

しかし間に余計なコライダーがいくつもあってRayが遮られてしまい、取得したいオブジェクトにRayがあたらない!なんてことありませんか?
そんな時は例えば以下のような対処法が挙げられます。

1. Physics.RaycastAll(Physics2D.RaycastAll())を使う

docs.unity3d.com
docs.unity3d.com

Raycastの結果を受け取る配列を用意し、そのすべてをforeach文で検証していきます。3Dと2Dで受け取り方が微妙に違うので注意。ただしforeach文での探索はコストがかかるので毎フレーム行う場合にはお勧めしません。

2. collider.RayCast()を使う

docs.unity3d.com
飛ばしたRayのうち、「このコライダーだけを探せ!」というような処理をすることができます。最初から探したいオブジェクトが決まっていればこちらを使うと早いです。1. よりもコストはかかりませんが、探したいオブジェクトが決まっていない場合には少々使いずらいです。

というわけで、今回は後述する3. の方法がメインの話となります。


3. LayerMaskを指定してオブジェクトを探索する。

実は最初に挙げたPhysics.Raycast(Physics2D.Raycast)には引数がいくつかあり、その中に引数でLayerMaskを設定できます。これは、入力したint値のレイヤーマスクのみを判別するというものです。
これは便利!!ということで試してみます。
f:id:covory10101101276:20200507200718p:plain
Layer 8に「sphere」を設定
f:id:covory10101101276:20200507200818p:plain
sphereにレイヤーを設定
f:id:covory10101101276:20200507200933p:plain
コードはこんな感じ。21行目のPhysics.raycastの第五引数にレイヤー番号8を入れる。

が、
f:id:covory10101101276:20200507200910p:plain
いくら押しても反応しない。。。。
レイヤー番号は0からだけど引数指定するときは1からなのか?とかバカなこと考えて数字を前後させてみたがダメ。IgnoreRaycastレイヤーは無視されるらしいからそれを抜いた番号なのか?とかアホなこと考えてさらに前後にずらしてみたが反応なし。。。

なぜだ。。。
しばらくネットで情報を探すと(というか一周してリファレンスを見返すと)
f:id:covory10101101276:20200507201954p:plain
DefaultRaycastLayersってなんだ? 普通に考えたら0か...?

docs.unity3d.com
3Dの方は特に目を引く記述はなかったが、
docs.unity3d.com
「マスクの値は IgnoreRaycastLayer マスクのビット補間に相当します。」
2Dの方に気になる記述を発見。ビット補間..?


どうやら、このLayerMaskの値は2bit値で管理されているようです。なのでこの引数に送るのは我々がよく認識する10進数ではなく、2進数での値のようです。
しかも単純にレイヤー番号を2進数にするわけではありません。例えば今回の場合はレイヤー番号は8なので2進数に直すと1000ですが、これも違うのです。
レイヤー番号はビットフラグという管理のしかたがされているようで、普通の管理番号をビットシフトする必要があります。
シフト演算
もうすでに文系の私は意味不明です。
が、これによると1から0を「8」つ増やした値を10進数に直した値が今回のLayerMaskの値ということになります。
ビットシフトはコーディングする際に簡単な方法があり、
f:id:covory10101101276:20200507204317p:plain
21行目にあるように 「1 << レイヤー番号」で求めることができます。


これで試すと....
f:id:covory10101101276:20200507204503p:plain
できました!長かった。。。。



こんなのわかんねーよー。しかもその説明にリファレンスからたどれないし。。。
なんとか仕組みが分かったーでも面倒だなーみんなこんなこと入力してんのか...ん?
docs.unity3d.com
f:id:covory10101101276:20200507205054p:plain
f:id:covory10101101276:20200507205003p:plain



f:id:covory10101101276:20200507205301j:plain




今回はここまでにしておきます。。。