この前のVRアカデミーで使ったプロジェクトデータで、初めから書いてあったコードで気になったところがあったので自分なりに色々してみた。
レイヤーとビット演算
当たったら呼ばれる OnCollisionEnter() 関数の中に
public class Arrow : MonoBehaviour { public LayerMask _hitableLayer; ・・・ void OnCollisionEnter ( Collision collision ) { if (((1 << collision.gameObject.layer) & _hitableLayer) != 0) { /* * 衝突したオブジェクトが _hitableLayerに含まれるとき。 * LayerMaskは複数のレイヤーを指定できてInspector上では扱いやすいが、 * データ上はビット演算になっていて、直感的でない。 * 指定のレイヤーにだけ反応するようにするには、上記の書き方をすると効率的。 */ 「指定したレイヤーとぶち当たったレイヤーが同じだったときの処理」 } else { 「それ以外のレイヤーにぶち当たったときの処理」 } }
と書いてった。
if (((1 << collision.gameObject.layer) & _hitableLayer) != 0) { }
これなんだろう、、、見たことない書き方だなあ。<< や & を使ってるからビット関連かな、、、
ログに出して見た
Sample
void OnCollisionEnter ( Collision collision ) { Debug.Log ("shift operation : " + ((1 << collision.gameObject.layer))); Debug.Log ("_hitableLayer : " + _hitableLayer.value); Debug.Log ("bit operation : " + ((1 << collision.gameObject.layer) & _hitableLayer)); if (((1 << collision.gameObject.layer) & _hitableLayer) != 0) { ・・・ } else { ・・・ } ・・・ }
「if文の条件が成り立ったときのログ」
」
「if文の条件が成り立たず else文のときのログ
_hitableLayer は public な変数で、Unityエディタから "Target" というレイヤーが選択されている。Tags & Layer からUnityに設定されているLayer一覧をみてみると、
となっていて、Target は8個目(0を入れると9個目)に設定されていた。
Debug.Log ("_hitableLayer : " + _hitableLayer.value);
のログでは 256 とでている。なんで "Target" から 256 が?きっと2進数からきてるのではないだろうか。
256 は 2の8乗。Target は8個目にあった。ここが関係してるのかと。
8 7 6 5 4 3 2 1 0 (桁)
1 0 0 0 0 0 0 0 0 (2進数) = 256(10進数)
1 << collision.gameObject.layer
というところはシフト演算なので、collision.gameObject.layer の値だけ 1 をシフトさせる。
Target レイヤー以外は Default レイヤー(0番目)で設定されているので 1 のままでシフトしない。よってログでも 1 が出力されている。
Target レイヤー(8番目)にあたったときは、8回シフトするので、
1 (0回目)
10 (1回目)
100 (2回目)
1000 (3回目)
10000 (4回目)
100000 (5回目)
1000000 (6回目)
10000000 (7回目)
100000000 (8回目) = 256(10進数)
よってログで 256 と出力されている。
この 1 か 256 の値と、_hitableLayer (256) を & でビット演算すると、
「1のとき」
000000001
100000000 &
ーーーーーー
000000000 = 0(10進数)
よって、if (((1 << collision.gameObject.layer) & _hitableLayer) != 0) { } が成り立たなくなる。
「256のとき」
100000000
100000000 &
ーーーーーー
100000000 = 256(10進数)
よって、if (((1 << collision.gameObject.layer) & _hitableLayer) != 0) { } が成り立つ。
こんなやり方があったなんて...。ビット演算シフト演算なので効率は良さそうですね。これはいいこと知ったっ!
ちょっと文章で書くのきつかったです。。。わかりにくくてごめんなさい。
あぁ〜、大学で2進数とかビット演算とか習うけどこーゆーところで使うんだなあ。と大学の勉強のモチベにもつながりました。またなんか気になるところ解決できたら投稿します。
written by Akiyama