Posted at
Unity #2Day 24

自作Unity標準ライブラリUniCommonの紹介

More than 1 year has passed since last update.


ごあいさつ

こんにちは。プログラマの@keroxpです。ちょうどUnity歴は1年ほどになります。

今年は新卒で入ったLINEという会社を辞めてエモを追求するために1人で「黒羽のアリカ」という2Dスマホゲームを作りました。

今はARKitとiPhoneXの機能を使った「黒羽のアリカAR」という3Dアプリを作ったりしています。

3Dに苦戦中でまだこんな感じで途中です(ホントはこれの完成版を記事にしたかった…😫)

アリカさんの名前だけでも覚えて帰ってくださいw

それでは本題に入ります。


結論

年末年始でお忙しい方も多いでしょうから、短い結論から。


Unityでのコードの再利用について

Unityを始めてからいくつかのプロジェクトを作成してアプリを作成しているうちに、同じようなコードを度々書いていることに気が付きました。

Screenshot from Gyazo

流石に全部一から書き直しているわけではないですが、そのたびにファイルを気合コピペしたり、コピペだとコンパイルが通らないところを細かく修正したり…とだんだん面倒になってきました。

そこで、自分なりのまとまりがとれた「黒羽のアリカ」の開発で使用したコードの中からゲームに直接関係のないコードを取り出して別プロジェクト化ました。

Unityは2017.2からUnityPackageManagerというパッケージ管理機能が追加されるとアナウンスされているのですが、実際どういうものなのか2017.3の現在もよく分かっていないので、Unityライブラリを配布する方法として使い慣れたnpmを選択しました。将来的にUPM(?)が動き出したらそちらに対応します。

参考:Unityプロジェクトの自作パッケージ依存性管理をnpmで行う


インストール方法

MacならUnityプロジェクトルートで以下のコマンドを実行すればインストール完了です。

npm i unicommon --save

mkdir -p Assets/Plugins/Packages
$(npm bin)/unity3d--sync


ドキュメント目次

自分のScrapboxにドキュメントを作成してあります。全てではありませんが逐次更新予定です。

詳細な解説は機能目次から確認していただくとして、UniCommonの中から特に便利な機能を4つ紹介します。


便利な機能4選


Asyncs - お手軽非同期処理

Unityのなかで非同期処理を簡単に実行したいと思ったことはありませんか?


Asyncsを使えば1行で簡単に非同期処理が実装できます。

 // 返り値なし

Asyncs.Execute(() => {
// ファイルIOとかの重い処理
}, () => {
// 完了。メインスレッドで受け取れる。
});
// 返り値あり
Asyncs.Execute(() => {
// 重い計算?
return 1
}, result => {
// result => 1。メインスレッド
});

Executeメソッドには、ActionもしくはFunc<T>を引数に渡し、バックグラウンドで非同期処理を実行してその結果をメインスレッドで受け取れます。


Loggers - お手軽ファイルロガー

LoggersはUnityのILoggerを実装したロガーのファクトリです。以下のように作成することで、メタデータが付与されたフォーマットでログ出力できるロガーをすぐに作成できます。


var logger = Loggers.New("MyClass");
logger.Log("MyMeshod", "way");
// => 2017-12-24 20:59:53+09:00 230ms/433F <L> [MyClass/MyMethod]: way

同様に、ファイルロガーも簡単に作成できます。ファイルへの書き込みはAsyncsを経由してバックグラウンドで実行され、指定インターバルごとに行われるため、アプリケーションのパフォーマンスを落とすことはありません。

var logpath = Application.dataPath + "/logs/my.log";

// 30秒ごとにflush
var fileLogger = Loggers.NewFileLogger("tag", logpath, TimeSpan.FromSeconds(30));
fileLogger.Log("MyMethod", "way");
// ファイルに"2017-06-01 20:59:53+09:00 230ms/433F <L> [tag/MyMethod]: way"と書き込まれる


Files - お手軽 & 安全なファイルIO

Filesには、ファイルIOに関した便利なメソッドがあります。

Files.TryWriteは指定パスにデータを同期的に書き込みます。


Files.TryWrite(Application.dataPath + "/save.dat", data);

Asyncsと併用することで非同期保存が可能です。

Asyncs.Execute(() => {

Files.TryWrite(Application.dataPath + "/save.dat", data)
}, () => {
Debugs.Log("保存完了");
});

Files.TryReadは指定パスのファイルを同期的に読み込みます。

var data = Files.TryRead(Application.dataPath + "/save.dat");

Asyncsと併用することで非同期読み込みができます

var path = Application.dataPath + "/save.dat";

Asyncs.Execute(() => Files.TryRead(path), data => {
// 読み込み完了
});

FilesのIOメソッドはちょっとした工夫をしていて、書き込み時に指定パスのすでにあるファイルが消失も破損もしないようになっています。


Crypter - お手軽暗号化

Crypterは、秘密鍵を用いた暗号化/復号化を簡単に実装できるクラスです。

このように使います。

// クリプタを作成

var crypter = Crypter.Default(() => "secret");
// 暗号化
var encrypted = crypter.TryEncrypt(new byte[] { 0, 1, 2});
// 復号化
var decrypted = crypter.TryDecrypt(encrypted); // bytes[] { 0, 1, 2}

Crypterのファクトリに渡しているのは、秘密鍵のプロバイダです。暗号化/復号化を行う場合にこの鍵を利用します。これは次のような方法で実装できると思います。


  • C#に直書き

  • Unityのリソースファイルに書く

  • サーバー経由で貰う

  • iOS/AndroidネイティブライブラリにC拡張関数を書いてDLLから読み出す

  • などなど…


おわりに

明日はAdvent Calener最終日、Yuta_Nakano0902さんの「クリスマスに相応しい記事」の予定です。それではみなさま健やかに新年をお迎えください。