おれんじりりぃぶろぐ

きっと何者にもなれないエンジニアのブログ

Unityで作ったアプリで端末の電源ボタンを押してもアプリが復活する問題に遭遇した

現象

Unityで開発中のアプリにてAndroidの特定端末でタイトルの現象に遭遇しました。 アプリ起動中に電源ボタンを押してサスペンドさせても数秒後に勝手にロック画面も表示されずアプリが復活してしまうという現象です。 なんと自己主張が強いアプリです。

対処法

BuildSettingsのDevelopment Buildにチェックが入っていたのでOFFにしたところ現象の発生はなくなりました。 全ての端末で起きるわけでもなくAndroidの特定の端末のみで起こるので厄介な問題でした。 (今回、自分が試した端末はAsus Zenfone5でAndroid Nでした) Android ManifestのOrientationとか色々いじりましたが、Unityの余分な仕様というオチでした。

参考

現象は少し異なりますが対処方法は同じでした。

Unityを使って女の子二人を動かすまで

成果物

f:id:orange_lily27:20180801014559g:plain

使用したツール

やったこと

MagicaVoxcelを使って簡単なモデリングをし、blenderでリギングを行いました。さらに、Unityにインポートしてアニメーションをつけるまでを紹介します。

モデリング

MagicaVoxcelを使って頑張ってモデリングをします。 ひととおりモデリングが終わったら右下のobjで書き出しを行います。

f:id:orange_lily27:20180801015548p:plain

リギング

次にblenderを使ってリギングを行います。 こちらで紹介されている素体用のアーマチュアを使わせてもらいました。
アーマチュア、objの順に取り込んでボーンの位置合わせを行います。 右クリックでアーマチュアの頂点を選択することができ頂点移動ができます。 「Remove Doubles」で重複頂点を削除するのも忘れないようにします。
Editモードにすることで左ウィンドウに「Remove Doubles」が出てきます。 f:id:orange_lily27:20180801020420p:plain

Objectモードに再び戻します。 メッシュ -> アーマチュアの順に選択をします。順番が大切です。Shiftを押しながら選択することで複数選択できます。 Ctrl + Pで「Make Parent」->「Armature Deform With Automatic Weights」でメッシュをボーンに関連付けができます。

最後にFbxとしてExportします。

リギングに関してはMixamoという自動で行ってくれる便利ツールがあるのですが、頭が大きすぎるからか髪の毛と腕がくっついてしまって今回は使うことができませんでした。

Unity

さきほど作ったFbxをUnityにD&Dします。

InspectorでAnimationTypeをHumanoidにします。

Configureを押して緑の人間が出てきたら成功です。Musclesで各部位をスライドさせることで動作チェックも行います。これで同じHumanoidTypeのAnimationClipを使い回すことができます。

モデルに色がついていない場合は、MagicaVoxcelのObj出力時に.objと同時にできた.pngを使ってMaterialを作成します。 MaterialのShaderはMobile/diffuseにしてpng画像をセットします。

最後に動かすためにアニメーションを設定していきます。 Unity Chanの3DモデルのAnimation Clipを使いました。

今回はAnimationControllerを使用しないSimpleAnimationを使ってアニメーションをつけました。 こちらの記事を参考にさせてもらいました。

f:id:orange_lily27:20180801014559g:plain

参考

Googleドキュメントにソースコードを綺麗に挿入する

いくつか試しましたが、「Code Block for Google Docs」というアドオンが良かったです。

[アドオン] -> [アドオンを取得] -> 「Code Block for Google Docs」で検索して追加できます。
使い方は、[アドオン] -> [CodeBlocks] -> [Start]から整形することができます。
コードを選択して[Format]を押すと整形されます。

こんな感じで表示されます。 f:id:orange_lily27:20180518203417p:plain

UnityでGCの回数を計測する

GC.CollectionCount()を使ってGCの回数を取得することができます。 GC.CollectionCount(0)はプロセスを起動してからのGC回数を返してくれます。

int startGcCount = GC.CollectionCount(0);

// GCが走りそうな処理

Debug.Log($"GC回数: {GC.CollectionCount(0) - startGcCount}回");

JenkinsでHockeyAppへのアップロードを下流Jobにする

まえおき

JenkinsでHockeyAppへのバイナリアップロードを別ジョブとして切り離す方法です。
Jobを切り離さない場合、ジョブが失敗した時にビルド自体が失敗したのかアップロードが失敗したのか分かりづらい、さらにビルド時間とアップロードにかかる時間が一即多になってしまい純粋なビルド時間が分かりづらいといったことが起こってしまいます。

ビルドJob(上流Job) ---> HockeyAppへのアップロードJob(下流Job)

Jobを切り離すことで以下のメリットが期待できます

  • Job失敗原因が特定しやすい
  • Jobの実行時間が分かりやすくなる

やり方

まずは上流のビルドJobを作成します。 上流Jobでは成果物の保存を行います。

f:id:orange_lily27:20180505211103p:plain

[ビルド後の処理追加] -> [成果物の保存]を追加する

次にHockeyAppアップロード用の下流Jobを作成します。 f:id:orange_lily27:20180505211739p:plain

「ビルド・トリガ」で「他プロジェクトの後にビルド」を設定します。

次に上流Jobでの成果物をコピーします。 「CopyArtifactPlugin」を導入します。

[ビルド手順の追加]で[他プロジェクトから成果物をコピー]を選択して以下のように設定します。 f:id:orange_lily27:20180505212153p:plain

あとはビルド後の処理でHockeyAppへのアップロードをします。 HockeyAppへのアップロードはHockeyAppPluginを導入することで簡単にできます。

f:id:orange_lily27:20180506003851p:plain

以上でビルドJobとHockeyAppへのアップロードのJobを切り離して実行することができます。

UnityでSwitchのJoyConを使う

まえおき

switchのJoyConをUnityで使う方法です。 基本的には以下の記事を参考にしましたが、一部ハマった箇所があるのでメモしておきます。

http://baba-s.hatenablog.com/entry/2017

環境

  • Mac
  • Unity2018.1.b13

やり方

JoyConとMacBluetoothで接続します。

f:id:orange_lily27:20180428205243p:plain

右と左で別々のデバイスとして認識されます。

Edit -> ProjectSettings -> Inputで以下の設定します。 f:id:orange_lily27:20180428205031p:plain

f:id:orange_lily27:20180428205042p:plain

手元の環境では参考記事とAxisの番号が異なっていて、嵌ってしまいました。 こちらのアセットで簡単に確認することが出来ました。

Controller Tester - Asset Store

検出は以下できます。

float h1 = Input.GetAxis("Horizontal1");

Unityのマルチスレッド界隈のはなし

Unityでのマルチスレッド界隈について断片化した理解にとどまっていたので、自分なりのまとめを行ってみました。

まず非同期実装と並列プログラミングは分けて考えよう

  • 非同期実装は順番通りに処理を実行しない、逐次処理とは対比的な処理のことである
    • 非同期処理は通信などの重い処理を別スレッドに逃しメインスレッドを専有させないことを目的としている
  • 一方で、並列実装は比較的短い(1フレーム内で収まる)処理を複数のスレッド使って同時に実行することでマルチコアな物理ハードウェアのパフォーマンスを最大限に引き出そうというアプローチである
  • 非同期実装に適しているのがawait/async、Taskを使った方法である
  • 並列プログラミングの実装に適しているのがC#のParallelクラス、Unityが提供するC#JobSystemになる

C#JobSystem

  • 元々、UnityエンジンではWorkerThreadをコア数-1(例外あり)で持っていた、それをユーザーにも開放した形になる
  • 1フレームで収まる処理を並行的に行うのに適している
    • 通信やI/O待ちが発生する非同期的な処理には向かない
      • その場合には、後述するawait、Taskを使っての実装を行うのがよい
  • イテレーションを回すコレクションはC#のコレクションではなくUnityが独自に用意したNativeArrayというunsafeなコレクションになる
    • NativeArray以外にもNativeListなど順次実装されていくとのこと
    • C++の配列のように必要な領域をあらかじめ確保して必要なくなったら開放をしてあげる必要がある
      • そのため下手な使い方をするとメモリーリークを起こす
        • 一応デバック方法はあって、Editor上だとメモリリークを起こしているという警告が出る
  • C#のコレクションはメモリ上に離散的に存在するのでキャッシュヒット率がとても悪い、JobSystemではNativetiveArrayを使用することでメモリ上に連続的に展開を行いキャッシュヒット率を上げる
  • そのためintやstructなどのプリミティブ型に限られる
  • メインスレッド制約のあるUnityの通常のAPIは使えない
    • MainThreadで実行してくださいというエラーが出る
  • JobSystem上で動く専用のAPIが順次増えていく予定とのこと
    • 今のところ(2018.1.b13)専用のAPIが用意されできることは以下の3つである
      • NavMesh
      • RayCast
      • Transformの書換え
        • 逆に上記に上げる3つ以外のことは制約や煩雑さがあるため使わないほうが良いかもしれない、簡潔な記述ができるC#のParallelクラス(後述)を使ったほうがいいのではないだろうか
  • JobSystem内で戻り値を返す方法がやや煩雑な印象である
  • 詳しい使い方はこちらのブログ記事を参考にすると良いと思います

C#での非同期実装

  • C#5でasync/awaitというキーワードが導入された
  • awaitは文字通り「待つ」の仕組みを提供するものである
var task = SampleAsync(); // 実行
Debug.Log("Immediate Execution"); <- 即時実行される
await task;
Debug.Log("SampleAsync() compleated!"); SampleAsync()の実行完了を待って実行される
  • awaitにTaskクラスを組み合わせて使うことで 非同期実装が容易に実現できる
  • Taskは一連の処理をまとめるためのものである。1つのTaskをメインではない別スレッドで丸っと実行させるということも簡単に実現できる
  • awaitは特定の条件を満たしたクラスに対して使うことができ、Taskがその条件を満たした実装になっているので使用が可能となっている
  • 条件を満たすように実装を行えばawaitをTask以外にも利用でき、例えばUnityコルーチンをawaitさせるということも可能である
  • WebHttpRequestなどは非同期実装が行いやすいようにTaskクラスを返してくれる非同期の通信メソッドがあらかじめ用意されている
var webReq = (HttpWebRequest)WebRequest.Create(URL);
await webReq.GetResponseAsync();

C#Parallelクラス

  • 並行プログラミングを簡単に実装できる仕組みである
  • 立ち位置的にはC#Jobsystemとオーバーラップする
  • UnityではC#JobSystemのほうがパフォーマンスは出るのでしょうが、簡単に記述できるという利点がこちらにはある
Parallel.For(0, N, i =>
{
    Debug.Log(i); // 複数のスレッドで同時並行的に実行する
});

参考

ここで書いたC#JobSystemの情報については、こちらの勉強会に参加して得た情報になります。