テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】ファイル名(アセット名)の一括更新について

Unityで作業をしていて、ファイル名の変更で少しひっかかったのでメモ。

ファイル名の変更とGUID

Unityでファイル操作を行う場合、ファイルの移動やリネームはUnityエディタで行う必要があります。

というのも、Unityは全てのファイル(アセット)にGUID(グローバル単位のユニークなID)を割り振り管理しているのですが、
Unity以外でファイルの移動やリネームを行った場合「ファイルが移動した」ではなく「ファイルが1つ消え、新しく別のファイルが作成された」と判断されGUIDが新しく割り振られます。そして結果としてGUIDから参照しているアセットがmissingになる為です。

f:id:tsubaki_t1:20160127225219j:plain

tsubakit1.hateblo.jp

なのでUnityが「移動した」「改名した」と判断できる、もしくは「改名してない」と判断できるようUnityエディタ上で変更するのが望ましいのですが、今回すこし問題が出ました。
つまり、対象のファイルが結構たくさんあった場合です。

f:id:tsubaki_t1:20160127225024j:plain

GUIDを操作しないようにファイル名を変更する

missingにしないためには、GUIDが変化しないようにリネームする必要がありますが、数が多いと非常に面倒です。たとえばキャラクター名をYukoとTokoで勘違いしてた場合など、ほぼすべてのファイル名の一部に変更が入ります。

GUIDが更新されるタイミングは色々とありますが、基本的には.metaファイルが新しく生成されたタイミングですので、.metaファイルが新しく生成されない限りはGUIDが更新されません

なので、ファイルを更新する際「ファイルと同名のメタファイルも同じ名前に更新」すれば、GUIDが更新されずmissingになる事はありません。少なくともmetaで管理してる方式ならば。

f:id:tsubaki_t1:20160127230030j:plain

このmetaファイルですが、初期設定では隠しファイルなので、表示してやるのが色々と良さそうです。
表示するにはメニューバー>ProjectSettings>EditorVersion ControlModeVisible Meta Filesに設定です。

f:id:tsubaki_t1:20160127230339j:plain

本当はエディタ拡張でやろうと思いましたが、普通に.meta更新した方が楽だし応用が効いたのでお蔵入り。

関連

madnesslabo.net

【Unity】AnimationClipのMissingなパスを見つけて解決しやすくするエディタ拡張

f:id:tsubaki_t1:20160126003924j:plain

昨日の応用で、アニメーションするオブジェクトでmissingになっているパスを発見し置換するエディタ拡張を作ってみました。

missingなAnimationClip

階層のあるアニメーションを作成した後、アニメーションを設定したオブジェクト名を変更すると、アニメーションの項目にmissingと表示され、アニメーションが正常に動作しなくなります。

例えば、Canvas/Image/Textという構造のアニメーションがあったとします。
それぞれのオブジェクトにはアニメーションが割り当てられており、CanvasはキャンバスのON/OFF、Image(背景)は半透明化、Labelは文字のIN/OUTのアニメーションが設定されています。

f:id:tsubaki_t1:20160126004456j:plain

さて、Typoリファクタリングの目的で、このアニメーションのCanvas/Image/LabelをCanvas/Background/Labelに変更してみます。

すると、Image以下のアニメーションへのパスがmissingとなり、Image以下のアニメーションが再生されなくなります

f:id:tsubaki_t1:20160126013424g:plain

さらに言えばエラーは特に表示されません。動かない場合、AnimationWindowにてAnimatorに登録されているアニメーションで動かなかったものを片っ端から確認する必要があります。*1

一応、Avaterを持つアニメーションの場合、Avaterが持つパスと一致しなかった場合warningを出してくれたと思いますが、残念ながら手付けでアニメーションを行って居た場合、オブジェクト名を変更するとこうなります。

なお、このパスによるmissingはルートオブジェクトには発生しませんコンポーネントさえ一致してれば、問題無く動作します。

missingなアニメーションを見つける

missingなアニメーションを見つける方法ですが、昨日の記事でGetCurveBindingsで確認する事が出来ます。つまり、

  • GetCurveBindingsでアニメーションの持つパスを全て取得する
  • Animatorが持つパスとBindingを比較する
  • Bindingとパスが一致しない場合、missingになっている

という事です。この条件でAnimatorに登録されているAnimationClipのBindingをどんどん漁っていきます。

f:id:tsubaki_t1:20160126005832j:plain

パスの比較はtransform.Findを使います。これならば、子オブジェクトしか見ないので一致するパスを別の親が持っていても誤検知する事はありません。
またGameObjectが非アクティブな場合も取得できる点、プレハブの階層でもを確認出来るので、中々に優秀です。

f:id:tsubaki_t1:20160126005519j:plain

missingなパスを置換する

missingなパスを見つけたら、それを修正します。
やり方は文字列置換的にパスを直すアプローチにしました。色々と考えましたが、良いGUIなアイディアが浮かばなかったので。
例えばRoot/Image/TextがRoot/Background/Textに変化しているのであれば、Image/TextをBackground/Labelに直してやれば良いって感じです。

f:id:tsubaki_t1:20160126010809j:plain

導入とソースコード

Editorフォルダを作成して、下のコードを配置します。

gist.github.com

f:id:tsubaki_t1:20160126011156j:plain

使い方

  1. メニュー/Assets/ReplaceAnimatorMissingPathを選択します。
  2. animatorにAnimatorコンポーネントの付いたオブジェクトを登録します
  3. missingになってるパス一覧が表示されるので、それと実際のパスを比較しながら間違っているパスの間違ってる部分を置換するようにreplace pathに記述します。パスの比較は目視で。
  4. Applyを押すとパスが更新されます。

f:id:tsubaki_t1:20160126013738g:plain

感想

実際は、Hierarchyが変化したらパスを追従するとか、プロジェクト内のプレハブ・シーンに設定されたAnimatorを片っ端からチェックするってエディタ拡張を作った方が有用かも。

関連

tsubakit1.hateblo.jp

 
 

*1:これが一番問題だと思う

【Unity】Unity 5.3以降でAndroidのStatus Barを表示する方法

f:id:tsubaki_t1:20160123024533p:plain

Unity 5.3で個人的に気になった機能まとめ 」に書いた通り、Unity 5.3にて何故かAndroidでStatus Barを表示するオプション…例えばstatus bar hiddenが一切使用出来なくなり、ステータスバーを表示する事が出来なくなりました。

ステータスバーを表示するのが最近の主流ではなくなってきたとは言え*1、結構な数のアプリがステータスバー表示を行っているので、一応これの出し方について書いてです。

Androidでステータスバーを表示する方法

Androidでステータスバーを表示するために、Androidのネイティブな機能を直接操作します。これが「使用しても良い方法」なのかは正直微妙な所ですが、一応動くのでまぁ、自己責任で*2

このネイティブへアクセスするコードを頑張って書いても良いのですが、既に機能を纏めて公開してくれているコードがあるので、それを拝借します。

github.com

ApplicationChrome.csを導入して、アプリの任意のタイミングで下のようなコードを呼ぶと、そのタイミングからステータスバーが表示されます

ApplicationChrome.statusBarState = ApplicationChrome.States.Visible;

また単純に「表示・非表示」だけではなく、色や不透明・半透明の指定も可能みたいです。半透明の場合、画面サイズが少し上に伸びるので、その辺り注意です。

f:id:tsubaki_t1:20160123033613p:plain

ついでにApplicationChrome.csはナビゲーションバー(画面下に表示される仮想ボタン)の表示・非表示・透明表示な制御も出来るので、ナビゲーションバーが必要なアプリケーションでも意外と重宝するかもしれません。

f:id:tsubaki_t1:20160123033746p:plain

アプリ起動時にステータスバーを表示する

次にアプリケーション起動時にステータスバーを指定するアプローチについて考えてみます。
単純に考えると、最初に起動した際のシーンにて読み込むアプローチが考えられますが、このアプローチだと最初のシーンが表示された後にステータスバーが表示されます。

RuntimeInitializeOnLoadMethodなる起動時にメソッドを読むAttribute(属性)もありますが、これも同様に最初のシーンが読まれた後にステータスバーが表示されます。

もう少し前の段階で読むアプローチとしては、ScriptableObjectとして作成しておき、PreloadObjectに登録、OnEnableでステータスバーを表示するアプローチです。

【Unity】ゲーム起動直後に1度だけ処理を行う の応用ですが、少しだけ前にステータスバーが表示されます。

f:id:tsubaki_t1:20160123035234p:plain

ここまでするならActivity書き換えちゃうのが良いきもします。
もしくは、無理にステータスバーを表示するよりも、演出で少し間を持たせる方が、プレイヤーにとっては健全なような気がしますが、どうなんでしょう。

AndroidiOSの整合性

このまま単純な実装ですとiOSAndroidのステータスバーを双方設定しなければいけないので、若干クールではありません。なので、Androidでステータスバーの表示・非表示を設定したらiOSも反映させるようにしてみます。*3

f:id:tsubaki_t1:20160123041928g:plain

実際は異なるブランチで開発している、もしくはプラットフォーム切替時に何らかの処理を走らせると思うので、余りここに意味は無いと思いますが一応。

ScriptableObjectでパラメータを設定している場合、ScriptableObjectのパラメータ変更時にPlayerSettingsも変更してしまいます。

OnValidate ()はScriptableObjectでも動作するので、こういったときに便利です。後はUnityEditor.PlayerSettings.statusBarHiddenUnityEditor.PlayerSettings.iOS.statusBarStyleOnValidate ()時にScriptableObjectの値と一致するような形に変えてしまえば、iOSAndroid間で整合性は取れそうです。

ソースコード

設定が面倒くさいので、プロジェクトごと公開します。

github.com

関連

ApplicationChrome.csの提供元

Unity tidbits: changing the visibility of Android’s navigation and status bars, and implementing immersive mode

zehfernando.com

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

forum.unity3d.com

*1:確認したら最近のゲームは意外とステータスバー表示してない

*2:Unity公式でサポートしなくなった以上、悪い方法に当たるとは思います

*3:理想ではPlayerSettingsの値を取れれば良いのですが、PlayerSettingsはUnityEditor以下のコードなので…

【Unity】Unityでマルチディスプレイする方法

f:id:tsubaki_t1:20151218224428j:plain
Unity 5.3でマルチディスプレイに対応したので、マルチディスプレイする方法について紹介します。

マルチディスプレイのための準備

マルチディスプレイを行う為には、幾つか準備が必要です。

まず、ディスプレイが二つ以上必要です。なにせマルチディスプレイですから。片方はラップトップ(ノートPC)でもOKですが、とにかく二つ以上です。

Unity側ではディスプレイは謙虚にも8個まで繋げる事が出来るみたいです。

f:id:tsubaki_t1:20151218224826j:plain

また、使えるのはスタンドアローン(PC向け)のみです。正確には、Windows/Linux/Macで動作するみたいです。
他のプラットフォームを選択中だと、マルチディスプレイの設定自体が非表示になります。

f:id:tsubaki_t1:20151218225303j:plain

またこれはMacですが、どうやらUnity 5.3f4の地点ではマルチディスプレイを使用するにはグラフィックAPIにOpenGL2を選択する必要があるみたいです。必要があるというか、バグっていてOpenGLCoreだとクラッシュします。
Auto Graphics API for Macのチェックを外すと、APIの優先順位を設定出来るようになります。

f:id:tsubaki_t1:20151218225553j:plain

マルチディスプレイを設定する

マルチディスプレイを設定していきます。
最初にエディタ内で画面を複数用意します。これは単純にGameビューを複数用意するって話です。

f:id:tsubaki_t1:20151218230243j:plain

Gameビューはビュー上の三からAdd Tabを選択しGameを選択すると、増やせます。

f:id:tsubaki_t1:20151218230047j:plain

あとは、どのGameViewをどのディスプレイに割り当てるかを決めます。Standaloneの場合はGameView上にディスプレイ番号があるので、それを使って選択します。
同一の番号の場合、内容がクローンされます。

f:id:tsubaki_t1:20151218230730j:plain

カメラを複数台設定する

カメラを複数台作成します。

f:id:tsubaki_t1:20151218231254j:plain

各々に割り当てるディスプレイ番号を設定します。もし同じディスプレイ番号をしている場合は、今まで通りDepthで描画順が決まります。

f:id:tsubaki_t1:20151218230922j:plain

これで各GameViewに各カメラが撮影した結果がそれぞれ反映されるようになりました。後は、実際にゲームで動かしてみます。

f:id:tsubaki_t1:20151218231411j:plain

マルチディスプレイを有効化する

マルチディスプレイを有効にするには、スクリプトが必要になります。
Display.displaysには認識している全てのディスプレイが表示されるので、それをActivate()してやればOKです。

gist.github.com

若干厄介なのがココで、ディスプレイ数が決まりきったシステムならば兎も角、ディスプレイ数が決まっていない場合は、ディスプレイに映すカメラの配置とかもココで調整する必要がありそうです。

また、何故かウィンドウモードで起動してからマルチディスプレイにした方が安定して動作する印象です。

マルチディスプレイにおけるマウス座標

マルチディスプレイでは、マウス座標を取得するためにはDisplay.RelativeMouseAt を使用します。ふざけたことに、これの戻り値x/yが座標、zがディスプレイ番号だそうです。

gist.github.com

なお、最もふざけたことはエディタで上のAPIが動作しないことです。

uGUIとマルチディスプレイ

最後にuGUIとマルチディスプレイについてです。

uGUIはScreenSpace-Overlayを使用している場合にどのディスプレイに映すのかを選択する項目が出現します。

f:id:tsubaki_t1:20151218234826j:plain

WorldSpaceやScreenSpace-Cameraはどちらも映すカメラを設定するので、ディスプレイ単位で選択することはありません。

面倒なのが、EventSystem標準で付いてくるモジュールがマルチディスプレイに対応していないらしく、2番以降のディスプレイに配置したUIに対して反応してくれません。

今後に期待…という事で。とりあえずコレもバグレポートかな

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp