tanaka's Programming Memo

プログラミングについてのメモ。

クリーンな状態のPCにUnity関連をインストールした時のストレージの容量ざっくりメモ

表題の通りのメモです。

やったこと 空き領域(GB) 消費容量(GB)
元の容量 97.7 -
Win10インストール 83.3 14.4
Chromeインストール 81.5 1.8
Unity Hubインストール 81.2 0.3
Unity2017.3(Mono Develop + Standard Assets + WebGL Build) 78.1 3.1
Unityでパーティクルをマウスに合わせて発生させるプロジェクト作成(+Windows Update?) 77.8 0.3

Visual StudioAndroid関連を入れないとUnityは3GBちょっと。比べてみると、Chromeってでかいんだな・・・。

さくらインターネットのPHPからgmailへ送信したメールが届かない

表題のママなのですが、SPF設定はしているし何だろう、とあれこれ調べてみました。結局、単純に怪しいメールだったから迷惑メールに振り分けられていた、ということでした...。迷惑メールフォルダーがデフォルトで表示されていないので、てっきり届いていなかったと勘違いしてました。

解決策

gmailを開いて、左の一覧の一番下のもっと見るを開くと、

f:id:am1tanaka:20180309181030p:plain

迷惑メールフォルダーがありました。

f:id:am1tanaka:20180309181255p:plain

このフォルダーを見ると、メールがちゃんと届いていて、「このメールは、迷惑メールのパターンに似ていたので迷惑メールにした」というようなことが書いてありました。

つまり、「オメーのメール、迷惑メールっぽいから迷惑メールにした」ということでした。

上にある「迷惑メールではない」をクリックして、解決しました。

f:id:am1tanaka:20180309181628p:plain

シェルのリダイレクトの備忘録

PHPからGitHubからプルを実行するためのコマンドに使うリダイレクトについて調べて理解できたことの備忘録です。

今回やりたかったことの最終形は以下です。

exec('/home/sakura_account/local/bin/git pull origin master 2>&1 1>/dev/null', $output, $return_var);

git pull origin masterGitHubにプルをする処理で、その後ろの2>&1 1>/dev/nullが肝心の部分です。

目次

目的

やりたいことは以下の通りです。

PHPexecコマンドは、第2引数に標準出力の結果、第3引数にステータスコードを返してくれます。以上から、標準出力は捨てて、標準エラー出力を標準出力にリダイレクトして$outputで受け取れば良さそうです。

リダイレクト

よく見る>/dev/null 2>&1とは

リダイレクトでよく見るのが>/dev/null 2>&1です。これは「標準出力(1)を/dev/nullに設定して捨てる」「標準エラー出力(2)を現在の標準出力の設定である/dev/nullに設定してやはり捨てる」という設定です。

これでは標準エラー出力も捨てられてしまうので、標準エラー出力は標準出力にリダイレクトする必要があります。

リダイレクトの要点

並べ方と設定内容があやふやだったので大混乱しました。自分的な要点は以下の2点でした。

  • リダイレクトは、左から右の順番で設定される
  • リダイレクト先は、設定時の状態が適用されて、それ以降の変更は前の設定には影響を与えない

特に2番目の理解が重要でした。

2>&1 1>/dev/nullとは

以上を踏まえた設定が2>&1 1>/dev/nullです。

  • 最初に2>&1を設定するので、標準エラー出力標準出力にリダイレクトされます
  • 次の1>/dev/nullで、標準出力を/dev/nullにリダイレクトして捨てます

標準出力を捨てる設定の方が後なので、標準エラー出力は先に設定した標準出力のままということになります。

順番を変えると?

順番を1>/dev/null 2>&1に変えるとどうなるでしょうか。リダイレクト元を省略すると、デフォルトで標準出力(1)が設定されるので、1>/dev/null>/dev/nullと同じ意味です。つまり、先に紹介したものと同じになるので何も表示されなくなります。

まとめ

設定した時点の状態のままというところがミソでした。標準エラー出力を標準出力に設定した後で、標準出力に加えた変更は、標準エラー出力には影響しないのですね。

参考URL

GitHubのWebhookをPHPで受け取る練習

WordPressのシステムの更新を、GitHubへのPushで自動化したくてその辺を調べてます。とりあえず、公式ドキュメントやらを読んで、ローカルにPHPで立てたサーバーでGitHubのWebhookを受け取ってみます。

目次

前提

  • GitHubにアカウントを持っていること
  • PHPがインストールされていること

ローカルサービスをインターネットからアクセスできるようにする

GitHubチュートリアルで紹介されているngrokを利用します。

  • ngrok - downloadを開きます
  • 動作させたいOS用のものをダウンロードします

f:id:am1tanaka:20180308210840p:plain

  • zipファイルを展開すると、実行ファイルが得られるので適当なフォルダーに入れます
  • コマンドプロンプトやターミナルで、ngrokの実行ファイルを入れたフォルダーを開きます
  • 以下で、http://localhost:4567をインターネットに公開します
ngrok http 4567

以下のような表示が出れば成功です。

f:id:am1tanaka:20180308212045p:plain

Forwardingとある横に表示されているhttp://3baeb856.ngrok.ioのURLで、8時間弱、インターネットからアクセスが可能になったということです。このURLをGitHubのWebhookに設定すれば実験ができます。このURLは毎回ランダムで変わりますので、表示されたURLに読み替えてください。

GitHubでwebhookを設定

GitHubに練習用のリポジトリーを作成して開いておきます。以下の操作をして、webhookを設定します。

  • Settingsタブを開きます

f:id:am1tanaka:20180308203456p:plain

  • Webhooksをクリックします

f:id:am1tanaka:20180308203705p:plain

  • Add webhookをクリックします

f:id:am1tanaka:20180308203856p:plain

  • 認証が必要なので、GitHubのパスワードを入力してConfirm passwordをクリックします

f:id:am1tanaka:20180308204056p:plain

  • 以下のように設定します
    • Payload URL欄には、ngrokで公開したURLの後ろに/payloadをくっつけた文字列を設定します。上記の例だとhttp://3baeb856.ngrok.io/payloadです
    • Content Typeは、application/jsonにして、JSONで受け取るようにします
    • Secretは、セキュリティーのための文字列です。30〜40文字程度のランダムな半角英数記号を設定します。自分で適当に入力しても良いですし、https://identitysafe.norton.com/ja/password-generator#などで自動生成しても良いでしょう。このサービスでは32文字までのパスワードワードを生成できます

f:id:am1tanaka:20180308213150p:plain

生成したパスワードは、GitHubとサーバーの双方で利用するのでどこかに書き写しておきましょう(以下に例示したものではなく、自分で生成したものに読み替えてください)。

f:id:am1tanaka:20180308213321p:plain

ここまでは以下のような感じです。

f:id:am1tanaka:20180308213459p:plain

  • 引き続きその下を設定します
    • Issuesイベントを設定するために、Let me select indivisual eventsを選択します
    • Issuesにチェックを入れます。pushはそのままでも構いません

f:id:am1tanaka:20180308213711p:plain

以上入力したら、Add webhookボタンをクリックして、webhookの設定完了です。

f:id:am1tanaka:20180308213925p:plain

作成が成功するとGitHubのページ上に以下のようなメッセージが表示されます。

f:id:am1tanaka:20180308214217p:plain

これで、練習用のリポジトリーにIssuesを登録すると、指定したhttp://????.ngrok.io/payload宛に、GitHubからpayload(ペイロード)と呼ばれるデータが送信されます。

webhookの送信テスト

動きを試してみましょう。まだサーバーは設定していませんが、上記のURLにアクセスがあればエラーが表示されて、とりあえず何かが届いたことは確認できます。

f:id:am1tanaka:20180308214722p:plain

  • New issueボタンをクリックします

f:id:am1tanaka:20180308214808p:plain

  • 適当な見出しを入力して、Submit new issueボタンをクリックして、Issueを作成します

f:id:am1tanaka:20180308215031p:plain

少しすると、ngrokにメッセージが届いて、以下のようなエラーが表示されます。

f:id:am1tanaka:20180308215203p:plain

/payloadに対してPOSTとGETのメッセージが届いたけど処理できなかった、ということです。届いたメッセージを処理できるようにします。

PHPでテスト用サービスプログラムを作成

GitHubからのpayloadを受け取るPHPプログラムを準備します。それに先立って、GitHubのWebhookを作成する時にSecret欄に入力したパスワードを環境変数に登録しておきます。Linuxmacの場合は以下のような感じでターミナルで実行します。

export SECRET_TOKEN="43jsoauslakjerlkasakdjfldsew"

上記で設定している文字は仮のものなので、実際にはGitHubに設定したものに差し替えてください。

Windowsなら、システムの環境変数などで設定すれば良いでしょう。

続けて、PHPのプログラムを用意します。

  • 開発するフォルダーを開いて、payloadというフォルダーを作成します
  • 作成したpayloadフォルダーの中にindex.phpを作成します

f:id:am1tanaka:20180309000412p:plain

  • 以下のコードを入力して保存します
<?php

// @copyright 2018 YuTanaka@AmuseOne
// @license https://github.com/am1tanaka/deploy-php/blob/master/LICENSE MIT
// 参考URL https://qiita.com/oyas/items/1cbdc3e0ac35d4316885

// ログファイルをこのフォルダーと同じ場所のhook.logに設定
$LOG_FILE = dirname(__FILE__).'/hook.log';

// 必要なデータを取得
$secret = getenv("SECRET_TOKEN");
$sig = array_key_exists('HTTP_X_HUB_SIGNATURE', $_SERVER) ? $_SERVER['HTTP_X_HUB_SIGNATURE'] : "";
$event = array_key_exists('HTTP_X_GITHUB_EVENT', $_SERVER) ? $_SERVER['HTTP_X_GITHUB_EVENT'] : "";
$body = file_get_contents('php://input');
$hmac = 'sha1='.hash_hmac('sha1', $body, $secret);

// 送られてきたSIGNATUREの長さが違う場合は
// セキュリティー対策で本来の長さの文字列に差し替える
if (strlen($sig) !== strlen($hmac)) {
    $sig = "";
    for ($i=0 ; $i<strlen($hmac) ; $i++) {
        $sig .= "a";
    }
}

// 認証
if (hash_equals($hmac, $sig)) {
    // 認証成功
    $payload = json_decode($body, true);
    file_put_contents($LOG_FILE, date("[Y-m-d H:i:s]")." ".$_SERVER['REMOTE_ADDR']." git issue recieved.\n", FILE_APPEND|LOCK_EX);

    // これ以降に実行したい処理を書く
}
else {
    // 認証失敗
    file_put_contents($LOG_FILE, date("[Y-m-d H:i:s]")." invalid access: ".$_SERVER['REMOTE_ADDR']."\n", FILE_APPEND|LOCK_EX);
}

 ?>

基本的な部分は@oyas様のGitHubのwebhookを受け取って、自動でgit pullするスクリプト - Qiitaから拝借しました。公式ドキュメントWebhooks | GitHub Developer Guideの記載に従って、タイミングアタックを防ぐためにハッシュ値の比較はhash_equalsに差し替えて、文字長が異なる時のチェックも加えたものです。

プログラムが準備できたので、サーバーを起動して動作確認をしましょう。

PHPの組み込みサーバーを起動

ターミナルでindex.phpを作成したpayloadフォルダーの一つ親のフォルダー(以下の場合、am1hpフォルダー)にcdで移動します。

f:id:am1tanaka:20180309000412p:plain

以下で、PHPの組み込みサーバーを起動します。

php -S 127.0.0.1:4567

準備ができました。GitHubの練習用リポジトリーで新しくIssueを追加するか、先に作成したIssueを編集してみてください。以下のようなメッセージがターミナルに表示されれば、何らかの処理が行われたことになります。

f:id:am1tanaka:20180309001507p:plain

index.phpと同じフォルダーに、hook.logというログファイルが出力され、その中に成功か失敗かが書かれているので、テキストエディターで開いてみてください。

f:id:am1tanaka:20180309001716p:plain

「git issue recieved.」と表示されていれば、GitHubからの正規なIssueイベントを受け取って、それを認証できたということです。

GitHub以外からのアクセスに反応しないことを確認

最後に、不正なアクセスをして、アクセスが拒否されることを確認します。Webブラウザーで以下を開いてください。

http://localhost:4567/payload

白い何も書かれていない画面が表示されれば動作完了です。このアクセスには正しいシグネチャーを持たないのでアクセスは拒否されているはずです。hook.logを確認してみてください。今度は以下のように「invalid access」というメッセージが書き込まれます。

[2018-03-09 00:19:25] invalid access: 127.0.0.1

つまり、認証が通らなかったので動作を拒否したということになります。

まとめ

以上でGitHubからWebhookを受け取って、認証する仕組みをローカル環境でテストしました。起動していたngrokとPHPの組み込みサーバーを[Ctrl]+[C]キーで停止して、ターミナルを閉じて構いません。

正規のWebhookかのチェックもしていますので、あとは必要な処理を認証成功時の場所に追加すれば良いでしょう。それはまた別でまとめます。

参考URL

2D Game KitのVFXController

am1tanaka.hatenablog.com

上記でまとめたObject Poolingは弾などのゲームオブジェクト用のプールシステムでしたが、パーティクルもまたプールシステムを持たせるべきものです。VFXControllerがそれに該当します。公式ドキュメントを読みながらのメモです。目次は私の方で勝手に入れたものです。

目次

このコンポーネントは、VFXプレハブをプールから生成して、既定の時間が過ぎたらそれらを停止して、プールに戻すために使います。

f:id:am1tanaka:20180220161325p:plain

VFXとは

"ゲーム業界ではエフェクト制作のことをVFXとよぶ場合もある"(VFX | CG用語辞典 | CGWORLD Entry.jp )。

2D Game Kitでは、一定時間ゲームに効果を与えて、時間が過ぎたら効果が消えるパーティクルによる演出全般のことを指しているようです。

VFXControllerはゲームで利用するすべてのVFXをリストで持たせて管理するアセットです。このアセットはVFXインスタンスのプールを事前に作成しておくことで、それらが画面に出現するたびにInstantiateによる負荷が発生しないようにします。

VFXを出現させるには、PlayerControllerStateMachineBehaviour TriggerVFXなどのスクリプトから、VFXController.Instance.Trigger()メソッドにVFXのプレハブ名や座標などを指定して呼び出します。

着地した場所や、着弾した場所のマップのタイルの種類に応じて、VFXを差し替えることもできます。例えば、足元にあるタイルの種類に応じて着地した時の土煙のエフェクトを変えることができます。VFXControllerの利用例は2D Game Kitプロジェクトを参照してください。DustPuff VFXは、プレイヤーが石の上を歩く時の土煙を設定しています。

f:id:am1tanaka:20180220164048p:plain

差し替えるタイルは、VFXControllerTrigger()メソッドの引数で渡します。例えば、着地処理では足元のサーフェイスを渡し、弾がサーフェイスに当たった処理では当たった場所のタイルを渡します。

タイルマップのオブジェクトではないタイルを上書きするように設定することもできます。GameObjectがどのように上書き設定をするべきかはサウンドのドキュメントであるSounds.txtを参照してください(訳注:Sounds.txtがどこにあるかわかりません。)

補足:実例を見る

公式ドキュメントは以上で終わりです。具体的な使い方がわからないので補足しておきます。

2D Game KitのHierarchyを見ると、VFXControllerオブジェクトが確認できます。

f:id:am1tanaka:20180220165912p:plain

VFXControllerオブジェクトは、VFX Controllerスクリプトがアタッチされているだけのオブジェクトです。

f:id:am1tanaka:20180220170038p:plain

VFX Controllerコンポーネントに、ゲームで利用するVFXをすべて登録します。デフォルトでは10個のパーティクルが設定済みです。中を見ると、JumpPuffDustPuffといったパーティクル以外に、EllenDeathなどのアニメーションのオブジェクトも設定されています。

f:id:am1tanaka:20180220161325p:plain

パーティクルに限らず、一定時間が経過したら自動的に消えるようにしたいエフェクトはすべてここに登録すればよいでしょう。

VFX Controllerの設定方法

利用するVFXをすべてこのオブジェクトに登録します。

f:id:am1tanaka:20180220175109p:plain

最低限設定するのは、VFXPrefabと、発生させてから効果を消すまでの秒数Lifetimeです。

VFXオーバーライドの設定方法

関連するタイルマップに応じてVFXを差し替えたい場合は、Vfx Override属性を設定します。

f:id:am1tanaka:20180220173347p:plain

  • Tile: 差し替える対象のタイルのルール
  • Prefab: 差し替えたいVFXのプレハブ

上記の設定をしてTrigger()を呼び出す時にタイルの情報を渡すと、通常はDustPuffVFXが発生しますが、足元がTilesetRockRolesだった場合は、GrassPuffVFXを代わりに発生させることができます。

VFXの発生方法

VFXスクリプトで指定します。一例をPlayerCharacter.csから抜粋します。

        public void PlayFootstep()
        {
            footstepAudioPlayer.PlayRandomSound(m_CurrentSurface);
            var footstepPosition = transform.position;
            footstepPosition.z -= 1;
            VFXController.Instance.Trigger("DustPuff", footstepPosition, 0, false, null, m_CurrentSurface);
        }

VFXControllerクラスのstaticメンバーであるInstanceを参照して、TriggerメソッドでVFXを呼び出しています。

VFXController.Trigger

Triggerメソッドの引数は以下の通りです。

public void Trigger(string name, Vector3 position, float startDelay, bool flip, Transform parent, TileBase tileOverride = null)
  • string name(あるいは int hash)
    • 発生させたいVFXをPrefab名か、int型のHash値で指定
  • Vector3 position
    • 発生させる座標
  • float startDelay
    • VFXの開始を遅らせる秒数
  • bool flip
    • trueの時、左右反転
  • Transform parent
    • 親のゲームオブジェクトがあれば指定。なければnull
  • TileBase tileOverride
    • マップタイルによってVFXを変化させたい場合、取得したタイルのインスタンスを渡します。変化が不要な場合は省略します

第1引数を名前で指定した場合は、内部でint型のハッシュ値を求めて参照しています。パフォーマンスにこだわる場合は、VFXController.StringToHash("VFX名")で値を求めることができるので、事前にint値を求めておいて、それを第1引数に渡すこともできます。

VFXOverrideをタイルマップ以外にするには

VFXOverrideのデータは、VFXController.csに以下のように定義されています。

        [System.NonSerialized] public Dictionary<TileBase, VFXInstancePool> vfxOverrideDictionnary;

TileBaseの種類によって検索が行われるようになっています。上記TileBaseの部分を変更すれば、他の型に変更が可能そうです。試してはいませんが、3Dゲームに対応させることもできるでしょう。

まとめ

VFX Controllerプレハブを設置してVFXプレハブを設定したら、Triger()メソッドで発生させるだけです。タイルマップを使ったゲームであれば、簡単にVFXのプール機能を実装できます。Object Poolingと同様にウォームアップはしてくれないので、自前で処理を追加するとさらに使えるようになりそうです。

インスタンスの管理にはObjectPoolingの仕組みを使っていますので、併せて理解することで応用の幅が広がりそうです。

参考URL

2D Game KitのObject Pooling

2D Game Kitは、プログラムコードを書かなくても結構な横スクロールアクションゲームが作れるUnity公式の素敵アセットです。ゲーム開発に役立つ機能が色々と実装されているのですが、パーティクルやゲームオブジェクトをプールして管理できるVFXController とObject Pooling機能は、スマホゲームなどを作る時にとても有用そうです。公式ドキュメントのObject Poolingを読んだ時のメモ(ほぼ訳)です。目次は私が適当に付けたもので原文にはありません。

(2018/3/5 ObjectPoolとPoolObjectの説明順が直感的ではなかったので、順番を入れ替えました)

目次

Object Poolingのための2つのクラス

2D Game Kitに実装されている拡張可能なObject Poolingシステムを使うには、2つのクラスを作成する必要があります。一つはObjectPoolクラスを継承したクラス、もう一つはPoolObjectクラスを継承したクラスです。ObjectPoolを継承したクラスはプールそのもので、PoolObjectを継承したクラスはプール内の各プレハブごとのラッパーです。

ObjectPoolPoolObjectの宣言

2つのクラスはGenericタイプで関連付けます。ObjectPoolPoolObjectの2つのクラスを型として持ったGenericタイプで宣言する必要があります。例えば以下のような宣言になります。

public class SpaceshipPool: ObjectPool<SpaceshipPool, Spaceship>
{

…

}

public class Spaceship: PoolObject<SpaceshipPool, Spaceship>
{

…

}

これにより、プールは自らが保持するオブジェクトのタイプを知ることができて、オブジェクトは自分がどのタイプのプールに属するかを知ることができます。

3つ目のパラメーター

これらのクラスは3つ目のGenericタイプをオプションとして定義することができます。このオプションは、PoolObjectがプールから取得される時に呼ばれるWakeUp関数に渡したいパラメーターがある場合に使えます。例えばスペースシップを登場させる時に燃料がどれぐらいあるかをfloatの値で指定する場合、以下のように定義します。

public class SpaceshipPool: ObjectPool<SpaceshipPool, Spaceship, float>
{

…

}

public class Spaceship: PoolObject<SpaceshipPool, Spaceship, float>
{

…

}

ObjectPool

PoolObject全体を管理するプールです。

ObjectPoolが持つフィールド

ObjectPoolMonoBehaviourであり、GameObjectにアタッチすることができます。デフォルトでは以下のフィールドを持ちます。

  • Prefab: プールを生成する時に複数回Instantiateされるプレハブへの参照です
  • InitialPoolCount: Startメソッドで最初に生成しておくPoolObjectの数です
  • Pool: PoolObjectのリストです

ObjectPoolが持つ関数

ObjectPoolが持っている関数です。

  • Start: 最初にプールが作成される時に呼び出されます。もしObjectPool内にStart関数を実装していた場合、ベースクラスのStartメソッドが隠されるので、必要に応じて呼び出す必要があることを覚えておいてください
  • CreateNewPoolObject: PoolObjectが生成される時に呼び出されて、SetReferencesを呼び出したら、関数をSleepします。この関数はvirtualではないのでオーバーライドはできませんが、protectedなので継承したクラスから呼び出すことができます
  • Pop: プールからPoolObjectを取得する時に呼び出されます。デフォルトでは、プールからinPoolフラグがtrueになっている最初のオブジェクトを見つけて、それを返します。inPoolフラグがtrueのものが一つも見つからなかった場合は、新しいオブジェクトを生成して返します。この関数は、取り出したPoolObjectWakeUp関数を呼び出します。この関数はvirtualなので、オーバーライドできます
  • Push: この関数は、PoolObjectをプールに戻す時に呼ばれます。デフォルトでは、inPoolフラグをtrueにして、PoolObjectが持つSleepを呼び出すだけです。この関数はvirtualなのでオーバーライドできます

詳しい利用方法については、以降のBulletPoolのドキュメントとスクリプトを見てください。

PoolObject

ゲームオブジェクトと一対一で対応するオブジェクトで、これのリストがObjectPoolで管理されます。

PoolObjectが持つフィールド

デフォルトでは、PoolObjectは以下のフィールドを持っています。

  • inPool: PoolObjectがプールにあるのか、利用されているかを表すbool値です
  • instance: このPoolObjectをラップしたプレハブからInstantiateされたゲームオブジェクトのインスタンスです
  • objectPool: このPoolObjectが所属するオブジェクトプールです。このクラスと同じObjectPoolのタイプを持ちます

PoolObjectが持つvirtual関数

PoolObjectは以下のVirtual関数を持ちます。

  • SetReferences: この関数はPoolObjectが作成された時に一度だけ呼び出されます。これは参照をキャッシュするためのもので、PoolObjectが利用状態になる度に毎回実行する必要がない1回だけ初期化すればよい処理のために利用します
  • WakeUp: PoolObjectがプールから取り出されて、利用状態になるタイミングで毎回呼ばれます。PoolObjectが利用可能になるタイミングで毎回行う必要がある初期化処理のための関数です。クラス定義で3つ目のGenericパラメーターが設定されていた場合、WakeUp関数に指定した型の引数を渡すことができます
  • Sleep: 利用しなくなるPoolObjectをプールに戻す際に毎回呼ばれる関数です。PoolObjectの利用後に毎回行う必要がある解放処理などのために使います
  • ReturnToPool: デフォルトではPoolObjectをプールに返すだけですが、追加の処理をしたい場合はこの関数をオーバーライドします

BulletPoolの解説

概要

BulletPool MonoVehaviourはBullet(=弾)のオブジェクトのプールで、弾プレハブのインスタンスを管理するものです。BulletPoolは主人公のEllenの両方で利用しますが、それぞれで少し違うものを使います。Ellen用のBulletPool MonoBehaviourは、親のゲームオブジェクトのPrefab欄に弾のプレハブを設定することでアタッチされます。敵用のBullet PoolEnemyBehaviourクラスで使われます。GetObjectPoolというstaticな関数を使って、インスタンスの生成をせずにBulletPoolが使えます。

BulletPoolが持つフィールド

BulletPoolクラスは以下のフィールドを持ちます。

  • Prefab: 利用したい弾のプレハブを設定します
  • Initial Pool Count: 開始時にいくつの弾を生成しておくかを設定します。同時に撃てる最大の弾数を設定しておきます。この数より多い弾を発射しようとすると、実行時に弾が生成されます
  • Pool: プール内のBulletObjectです。Inspectorには表示されません

BulletPoolが持つ関数

BulletPoolクラスは以下の関数を持ちます。

  • Pop: プールからBulletObjectを取り出します
  • Push: BulletObjectをプールに戻す時に呼びます
  • GetObjectPool: 指定したPrefabが設定されているBulletPoolを見つけるstatic関数です

BulletObjectが持つフィールド

プールから取得した弾は、BulletObjectのフォームとして渡されます。BulletObjectクラスは以下のフィールドを持ちます。

BulletObjectが持つ関数

BulletObjectは以下の関数を持ちます。

  • WakeUp: Pop関数が呼ばれた時にBulletPoolから呼ばれます
  • Sleep: Push関数が呼ばれた時にBulletPoolから呼ばれます
  • ReturnToPool: 弾の利用を終了する時に呼ぶことになっている関数です。この関数はBulletPoolPush関数を呼び出して、Sleep関数を呼びます

まとめ

公式ドキュメントはこんな感じでした。詳しくは実際のコードを見てください、という感じです。

シーンの開始時に必要なインスタンスをまとめて生成して、その後はそのインスタンスを使い回してくれるので、メモリーの確保と解放を繰り返すことによる速度低下や、メモリーの断片化を避けることが期待できます。予定数をオーバーした場合にも対応していて、超過した時はその時点でInstantiateしてくれる柔軟性を持っています。

WebGLスマホでは、オブジェクトの初回描画時に処理落ちすることがあります。それを避けるためには、シーンの開始時に、必要なオブジェクトを一度画面に描画するウォーミングアップ処理をするとよいようです( 【Unity】パフォーマンスチューニング - KAYAC engineers' blog )。デフォルトのままだとこの辺の対処はありませんが、Start関数に自前でコードを追加すれば対応できそうです。

再利用するオブジェクトは、動作速度を安定させるためには把握しておきたい要素なので、予めObject Poolingを導入しておけば、あとで膨大なプロジェクトの中から再利用しているオブジェクトを探し出す手間がなくなるので楽ができそうです。

参考URL

Projenyにカスタムのパッケージを登録する

Unity用のパッケージマネージャーProjeny、使い続けています。時々怪しい動きをしますがやはり便利です。

Asset Storeからダウンロードしたパッケージは自動的に読み込めますが、UnityちゃんやPost Processing Stack V2など、Asset Storeで配布されていない有用なパッケージもあります。そのようなパッケージをProjenyで扱う方法です。

目次

方法

とても簡単で、設定ファイルProjeny.yaml内で、ReleaseSources属性で設定したフォルダーに利用したいunitypackageファイルを入れておくだけです。

ファイル名はパッケージ名になりますが、@に続けてバージョン番号をつけると、バージョンを表示することができます。例として、"制服ユニティちゃん"のVer1.0を登録してみます。

設定の確認

Projeny.yamlは、ユーザーフォルダー直下と、プロジェクトフォルダーのものが読み込まれます。両方にProjeny.yamlがあった場合、一方にしかない設定はどちらのファイルのものも有効になります。両方に同じ設定項目が書かれていて、内容が違う場合は、2018/2/12時点ではプロジェクトフォルダーの方が採用されるようです。

まずは使いたいプロジェクトフォルダー内のProjeny.yaml、次にユーザーフォルダー直下のProjeny.yamlを開いて、以下のような設定を確認します。

ReleaseSources:
    - LocalFolder:
        Path: 'D:\Projeny\CustomPackages'

上記の場合、D:\Projeny\CustomPackagesフォルダーが、カスタムのパッケージファイルを入れておくフォルダーを表します。上記のような設定がない場合は、こちらを参考に、ユーザーフォルダー直下か、プロジェクトフォルダー下のProjeny.yamlファイルに設定を加えてください。

ファイルを用意する

ユニティちゃんの公式ページから、使いたいパッケージをダウンロードします。

  • UNITY-CHAN! OFFICIAL WEBSITEを開いて、"DATA DOWNLOAD"をクリックします
  • 規約を確認したら、画面下の"ユニティちゃんライセンスに同意しました"にチェックを入れて、"データをダウンロードする"ボタンをクリックします
  • 利用したいパッケージをダウンロードしてください。以降は"制服ユニティちゃん"を例に紹介します

f:id:am1tanaka:20180212010614p:plain

  • ダウンロードしたら、ファイル名を01_kohaku_B@1.0.unitypackageに変更します

f:id:am1tanaka:20180212010830p:plain

  • 名前を変更したファイルを、"ReleasePackages"設定のフォルダーに移動します。上記の例では、D:\Projeny\CustomPackagesフォルダーですが、ご自身の環境に合わせて変更してください

f:id:am1tanaka:20180212011010p:plain

以上で準備完了です。Projenyから利用できるようになりました。

Projenyで利用する

利用方法です。

  • コマンドプロンプトで、Projenyのプロジェクトフォルダーからprj -ouを実行するか、あるいはUnityを起動して、プロジェクト名-Windowsフォルダーを開いて、ProjenyのUnity Projectを開きます
  • "Projeny"メニューから"Package Manager..."を選択します

f:id:am1tanaka:20180212011326p:plain

  • パッケージマネージャーが起動したら、左三角ボタンを2回クリックして、Release画面を表示します

f:id:am1tanaka:20180212011547p:plain

  • Asset Storeのパッケージと一緒に、"01_kohaku_B"が表示されているのが確認できます。ファイル名で指定したバージョンが、v1.0と表示されていることも確認できます

利用するために、パッケージとして展開します。

  • Packages欄を、共有用の"SharedUnityPackagesDir"に変更してから、利用したい"01_kohaku_B v1.0"をドラッグして、Packages欄の一覧にドロップします

f:id:am1tanaka:20180212011846p:plain

  • 右三角ボタンを一回クリックして、”Project"設定を表示します
  • Packages欄の"UnityChanTPK"をドラッグして、Projectの"Plugins Folder"欄にドロップします(調整や改造など、変更を頻繁に行うような場合は、"Plugins Folder"よりも"Assets Folder"欄)

f:id:am1tanaka:20180212012341p:plain

  • "Update Directories"ボタンをクリックします

f:id:am1tanaka:20180212012429p:plain

以上で、加えたパッケージがUnityプロジェクトに反映されて、"Project"ビューに表示されるようになります。

f:id:am1tanaka:20180212012544p:plain

"Prefabs"フォルダーから"01_kohaku_B"を"Hierarchy"ビューにドラッグ&ドロップすれば、制服ユニティちゃんを登場させることができます。

f:id:am1tanaka:20180212014036p:plain

まとめ

ProjenyのReleaseSourcesで指定したフォルダーに、unitypackageファイルを配置することで、簡単にカスタムパッケージを複数のプロジェクトで利用できるようになります。

また、ファイル名に@を付けてバージョン番号を書いておくことで、異なるバージョンを保持することができます。プロジェクトにどのバージョンを読み込んでいたかが簡単に管理できるようになります。また、最新版に変更したら動かなくなった場合など、古いバージョンに戻すことも可能になります。

unitypackage形式になっていない場合は、Unityの通常のプロジェクトで開いてから、Export Packagesで必要なアセットを出力すれば使えるようになります。

よく使うパッケージを登録しておけば、毎回ダウンロードする必要がなくなるのでとても便利です。

参考URL

ライセンス

f:id:am1tanaka:20180212013017p:plain

この記事中のユニティちゃんは、ユニティちゃんライセンス条項の元に提供されています。