AizuVR blog

会津大学VR部の部員が持ち回りで投稿していくブログです。特にテーマに縛りを設けずに書いていきます!

「面白法人カヤックVR分室」としても活動しています。詳細はこちら

この前のVRアカデミーで気になったところ 〜その1〜

この前の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文の条件が成り立ったときのログ」
f:id:aizu-vr:20170306202511p:plain:w200

「if文の条件が成り立たず else文のときのログ
f:id:aizu-vr:20170306202510p:plain:w200


_hitableLayer は public な変数で、Unityエディタから "Target" というレイヤーが選択されている。Tags & Layer からUnityに設定されているLayer一覧をみてみると、
f:id:aizu-vr:20170306204049p:plain:w300
となっていて、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

会津大学VR部の部員が持ち回りで投稿していくブログです。特にテーマに縛りを設けずに書いていきます!