ゴミ箱

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

スマホカバーは甘え説

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

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

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

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

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

逆にスマホカバーをつけずに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