ゴミ箱

くだらないことからUnityの知識共有まで

ビット演算の考え方が面白い

ビット演算ってなんだ

Wikipedia先生より

ビット演算(ビットえんざん、bitwise operation: 直訳すると「ビット毎操作」)とは、固定長のワードなどといった「ビットのカタマリ」(コンピュータの数値表現なども参照)に対して、各のビット全てに対する論理演算をいっぺんに行う演算操作である。 実装の観点からは、現在一般的な二進法(ディジタル)式の電子式コンピュータでは、加減算ではビットあたり数個程度の論理ゲートに加え多少複雑なキャリー伝搬の処理が、乗除算では多段に渡る処理が必要であるのに対し、ビット演算は1個か高々2個の論理ゲートで行えるため、多くの場合、最短サイクルしか必要としない。そのことから、高性能なプログラムを実現するための機械語コーディングではビット演算の使いこなしは重要なテクニックである。

コンピュータの世界では全てのデータを二進数で扱っていて、ビットに対して演算を行う方法は高速な処理を実現できる。ってことですかね…。 私みたいにUnityからゲーム開発を始めた新参者にはなかなか想像しづらいのですが、普段使っているintなどもコンピュータ上では二進数で計算が行われているってことですね。 そして二進数で扱っているからこそできる演算方法がビット演算です。

十進数と二進数

f:id:blacker1017:20180225203712p:plain
前提知識として十進数と二進数の対応表を張っておきます。 見てわかる通り0と1で表されていて、なんかこう桁が上がっていくんですよ(語彙力)。 詳しくはググってください。

ビット演算の使用例

早速ですが実際にどんなときに使えるのかというと、複数のフラグを管理したいときです。 まずはビット演算を使わない例を下のコードに示します。言語はC#です。

public class Smple1
{
    public class ProgrammingSkill
    {
        public bool c = false;
        public bool cpp = false;
        public bool cs = false;
        public bool java = false;
        public bool php = false;
    }
    
    public static void Main()
    {
        ProgrammingSkill mySkill = new ProgrammingSkill();
        mySkill.cpp = true;
        mySkill.cs = true;
        
        OutPut("c", mySkill.c);
        OutPut("cpp", mySkill.cpp);
        OutPut("cs", mySkill.cs);
        OutPut("java", mySkill.java);
        OutPut("php", mySkill.php);
    }
    
    public static void OutPut(string skillName, bool skillFlag)
    {
        string temp = skillFlag ? "はできます!" : "はできません…";
        System.Console.WriteLine(skillName + temp);
    }
}

出力結果

cはできません…
cppはできます!
csはできます!
javaはできません…
phpはできません…

次にビット演算を使うと以下のようになります。 出力結果は変わりません。

public class Smple2
{
    public static int c = 1;    // 00001
    public static int cpp = 2;  // 00010
    public static int cs = 4;   // 00100
    public static int java = 8; // 01000
    public static int php = 16; // 10000
    
    public static void Main()
    {
        //! cppとcsのフラグを立てる
        int mySkill = cpp | cs; // 00110
        
        OutPut("c", (mySkill & c) != 0);
        OutPut("cpp", (mySkill & cpp) != 0);
        OutPut("cs", (mySkill & cs) != 0);
        OutPut("java", (mySkill & java) != 0);
        OutPut("php", (mySkill & php) != 0);
    }
    
    public static void OutPut(string skillName, bool skillFlag)
    {
        string temp = skillFlag ? "はできます!" : "はできません…";
        System.Console.WriteLine(skillName + temp);
    }
}

複数のboolフラグで管理していたmySkillが一つのintで表すこととができています。 考え方としては、intで保存している二進数はそれぞれの桁が必ず0か1なので0がfalse、1がtrueのフラグを桁数分持っていてそれによって判定を行う、ってかんじですかね。

実際に使う演算子をコメントで説明しようとして失敗しているのが下のコードです。 今回のようにintをフラグとして利用する時に使う演算の一例です。 理解できなかったらググってください…

public class Sample3
{
    public static void Main()
    {
        //! 0001 (1)
        //! 0010 (2)
        int temp = 1 | 2;
        //! 0011 (3) ←OR演算の結果
        
        //! 0011 (3)
        //! 0100 (4) 
        temp |= 4;
        //! 0111 (7) ←OR演算の結果
        
        //! 0111 (7)
        //! 1101 (2の反転)
        temp &= ~2;
        //! 0101 (5) ←AND演算の結果
        
        //! tmpは2のフラグが立っているか
        System.Console.WriteLine((temp & 2) != 0);
        //! 出力結果 False
        
        //! 最終的には1と4のフラグが立った状態
    }
}


終わりに

正直、Smple1のように複数のフラグをクラスで管理していた方がイメージしやすく拡張性もあると思うので、 Sample2のようなビット演算の使いどころは慎重に考える必要があると思います。 ただ、二進数のintを複数のフラグとする考え方は面白いと思ったので今回の記事を書きました。 こういう考え方もあるんだ、と知っていただけたら幸いです。

最後にSmple2にあるintのビットデータ宣言を簡単にする方法を以下のコードに記します。

public class Smple4
{
    public int c = 1;           // 00001
    public int cpp = c << 1;    // 00010
    public int cs = cpp << 1;   // 00100
    public int java = cs << 1;  // 01000
    public int php = java << 1; // 10000
}

「<<」はシフト演算?と言うらしいです。 意味としては1の位置を左に一個移動するってことらしいです。 ビットデータを一つずつ手で宣言するより正確なのでこっちをオススメします。

スマホカバーは甘え説

最近はあまり見ませんが以前はスマホの液晶画面にヒビが入っている人を多く見かけました。 実際私の友達も私の目の前で手を滑らせスマホを地面に落とし、液晶画面を粉々にしてくれました。

そういった液晶画面にヒビが入っている人は意外にもスマホカバーをしている人が多かったのです。 そこで一つの仮説が生まれました。

そう、スマホカバーは甘え説」です。

スマホカバーをしている人は心のどこかで"落としても大丈夫だろう"と、慢心が生まれます。 そして普段からスマホを雑に扱い、落としても液晶画面は無事だったというケースを多く経験してしまうことで、人はスマホを落とすことを完全に警戒しなくなっていきます。 こうなってしまうと事故が起きるのは必然と言っても過言ではないでしょう…(震え)

カバー以外にもバンカーリングなどの防衛装置も存在しますが、これらも装着することで慢心が生まれいずれスマホを落とし画面を割ります。

逆にスマホカバーをつけずに2年ほど使ったiPhone5s時代の私は一度もスマホを(腰以上の高さから)落としたことはありません。 これはスマホカバーをつけていないことでスマホを扱う際に必ず"落としてしまうのではないか"という警戒心があったからだと思います。

つまりスマホは何もつけないのが最&高なわけです。

みなさんもスマホにカバーやバンカーリングをつけている人は今すぐ外し、正常な警戒心を取り戻しましよう。 ちなみに私はスマホカバーについているパスケースを使うためだけにスマホカバーをつけています。 断じて甘えではありません。断じて。

※この記事を見てスマホカバーを外し画面にヒビが入ってたとしても、もちろん私は一切責任を追いません。

Unityでオブジェクトのpool化?

pool化とはなんぞや

poolとは...

ソフトウェアの分野では、プログラムの実行時に何度も繰り返し利用する資源をいちいち生成・破棄する手間を軽減するため、必要なくなった資源を回収してすぐに再利用できるように一時的に貯めておく仕組みや保管領域のことをプールという。

プールとは - IT用語辞典

きっかけ

昨日、ある知人(ミリオタ)がFPSゲーム作っていて
銃からでる弾をpool化していなかったので友人と考えながら実装しました。
今回はその実装内容を忘れないように書き残します。

そもそもpool化しない場合

まあ、銃から弾を出すわけですが
出る弾の数が決まっている訳ではないので、
「任意のタイミングで弾を生成する処理」と
「一定時間経ったら弾を削除する処理」が必要になります。

Unityでオブジェクトを生成するにはInstantiate関数を使います。
また、オブジェクトを削除するにはDestroy関数を使います。

実はこの二つの関数が問題です。

自分で検証したことはありませんが、
InstantiateDestroyは処理が重い」とよく聞きます。

そこで、pool化するわけです。

じゃあpool化したい…

pool化するとしても必要な処理は対して変わりません。

「任意のタイミングで弾が必要なら生成する処理」と
「一定時間経ったら弾を非表示にする処理」

生成は必要最低限だけにして削除せずに見えなくするってことです。
※本来は生成される最大数がわかってることが多いですが、
今回は最大数がわからないことを想定して動的に生成します。

下準備

先に発射される弾を作ります。
適当に球のオブジェクトを作って「bullet」に名前を変更します。

次に以下のコードを作成し適用します。

using System.Collections;
using UnityEngine;

public class BulletMove : MonoBehaviour {

    void Start()
    {
        StartCoroutine("ObjectSetActive");
    }

    // activeになったときもコルーチンを始める
    void OnEnable()
    {
        StartCoroutine("ObjectSetActive");
    }

    // コルーチン
    private IEnumerator ObjectSetActive()
    {
        // 2秒後にオブジェクトを非表示にする
        yield return new WaitForSeconds(2.0f);
        gameObject.SetActive(false);
        yield break;
    }

    void Update()
    {
        // 移動処理
        transform.position += Vector3.forward;
    }
}


そして、AssetsフォルダにResourcesフォルダを作成し
作ったオブジェクトをプレハブ化します。

これで下準備は完了です。

ようやく処理を書きます

また何かオブジェクトを作って、以下のコードを作成し適用します。

using System.Collections.Generic;
using UnityEngine;

public class BulletPool : MonoBehaviour {

    private GameObject BulletPrefab;

    // バイトメンバーリスト
    [SerializeField, Header ("弾のリスト")]
    private List<GameObject> Bullets = new List<GameObject>();

    void Start()
    {
        // Resourcesフォルダからbulletプレハブを取得
        // コイツがクローン体の素体
        BulletPrefab = Resources.Load("bullet") as GameObject;
    }

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            // 最初はバイトメンバーが0人なので
            // 必ず人員を追加する(きっとコイツがバイトリーダー)
            if (Bullets.Count == 0)
            {
                NewIns();
            }
            // それ以降はバイトメンバーリストで働いていないやつを探す
            else
            {
                bool insRequest = true;

                for (int i = 0; i < Bullets.Count; i++)
                {
                    // 休憩中のやつを探し出してしっかり働かせる
                    if (Bullets[i].activeSelf == false)
                    {
                        ReuseBullet(Bullets[i]);
                        insRequest = false;
                        break;
                    }
                }

                // Bullesリスト内のやつらが全員働いていたので
                // 仕方なく増員
                if (insRequest == true)
                {
                    NewIns();
                }
            }
        }
    }

    // 新しく弾を生成(増員)
    private void NewIns()
    {
        GameObject GO = Instantiate(BulletPrefab,transform.position,Quaternion.identity,transform);
        Bullets.Add(GO);
    }

    // 弾を再利用(「休憩は終わりだ!」)
    private void ReuseBullet(GameObject bullet)
    {
        bullet.transform.position = transform.position;
        bullet.SetActive(true);
    }
}


見てわかる通りリストを作って生成された弾を入れておいて、
任意のタイミングでリスト内で非表示のオブジェクトがあったら使いまわしています。

コメントアウトでは弾をバイト人員に見立てて
説明を面白くしようとしている努力が見られます…

うまく動作していると、
スペースキーを押した時に非表示のオブジェクトが
あれば使いまわし
なければ生成が行われます。

Unityでマルチタッチの情報が少ないと思ったら公式リファレンスにあった件

公式リファレンス↓

Unity - マルチタッチスクリーンの入力

つい先日までスマホゲームを作っていて、
二本の指それぞれの位置を別々に取得して
いろいろしたかったのです。

制作が終わって軽く調べていると以下のコードを見つけました。

using UnityEngine;
using System.Collections;

public class TouchTest : MonoBehaviour 
{
    void Update () 
    {
        Touch myTouch = Input.GetTouch(0);

        Touch[] myTouches = Input.touches;
        for(int i = 0; i < Input.touchCount; i++)
        {
            //タッチすると行う何かをここに記入
        }
    }
}

公式リファレンスより

全てはここに集約されてました。
つまりTouch変数にそのフレームで取得している全ての指の情報が入っていたわけです。
わかりやすくこれをいじって…

using UnityEngine;
using System.Collections;

public class TouchTest : MonoBehaviour
{
    //Canvasで適当にImageをたくさん作って配列に入れてください
    public Transform[] Image;

    void Update()
    {  
        if (Input.touchCount > 0)
        {
            //touchCountが0のときに呼ばれるとエラーでます
            //このフレームでのタッチ情報を取得
            Touch[] myTouches = Input.touches;

            //検出されている指の数だけ回して
            //指の位置にImageを移動
            for (int i = 0; i < myTouches.Length; i++)
            {
                Image[i].position = myTouches[i].position;
            }
        }
    }
}

f:id:blacker1017:20170722232443p:plain
こんな感じに配置して実行すると…
f:id:blacker1017:20170722233349g:plain
超簡単にマルチタッチが実装できました!

分かりずらいですが、
赤い板が一本目、緑の板が二本目、青の板が三本目の指に追従しています。

実行してもらえばわかるのですが、
二本タッチして一本目を離すと、
二本目の指が一本目扱いになります…(意味深)

これを回避するために、
一本目が離れたときに二本目と入れ替えるとか
いろいろ頑張ったのですが結局今回のゲームでは
仕様変更で無駄になりました…
この頑張りを次回にでも書こうかなと思います。

補足

ちなみに普通はUnity Editor上でマルチタッチはできません。
画面タッチに対応しているPCだとEditor上で動作します。
もちろんAndroidiOSにビルドすれば問題なく動作します。
お気を付け下さい…

<動作環境> Surface pro4,windows10,core i7,8GB