テラシュールブログ

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

【Unity】Androidにプロファイラを接続しても内容が更新されない時の対処法

プロファイラを接続しても更新されない

f:id:tsubaki_t1:20160806225050j:plain

AndroidでProfilerを使用していた際、プロファイラが何も情報を表示してくれなくなる事がありました。いつもなら接続した後にプロファイラがパフォーマンスについて色々と出してくれるのですが、接続してもプロファイラが更新されません。

一応、プロファイラの再起動等も試してみても効果はなし、しかし接続はできてるっぽい。

「以前は表示してくれたのですが…」

原因は他のアプリが既にプロファイラに接続していた為(?)

原因はどうやら、別のアプリがプロファイラを使用していたせいでした。

つまり、以下のような手順で再現出来ます。

  1. アプリAを起動し、プロファイラを接続
  2. アプリBを起動し、プロファイラを接続(反応無し) ←今ココ

今回の自分が発生したケースでは、幾つかのアプリをBundle Identifierを差し替えながらビルドしていたのですが、以前接続した状況が残っていたため接続出来なかったみたいです。

以前プロファイラが接続してたアプリを落とせば接続可能

プロファイラが接続してるアプリを終了させれば、アプリBにプロファイラが接続出来るようになります。

つまり上記の例だと、アプリAを落とせばアプリBが繋がるようになりました。

f:id:tsubaki_t1:20160806225518j:plain

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

【Unity】目的地へ辿り着くための矢印を表示する

f:id:tsubaki_t1:20160803232953j:plain

今回は、ゲームで道に迷った(哲学的な意味ではない)際の目安となる、目的地への道順を示す矢印の表示についてです。

ゲーム進行の矢印

2Dアクションゲームでも、3DRPGでも、目的地が何処にあるのか分からなくなると簡単にクソゲーなります

 

ということで、出来る限りゲームをスムーズかつ簡単に体験して貰うために、道を示すというのは中々に悪くない選択肢です。多分。
まぁ、AAAなゲームではステージの配置やライティング、カットシーン等により「ユーザー自身の気づき」で移動先を見出すのが最もクールだと思いますが、ソレを見落として道に迷った末に止めたゲームを自分は何本か持っています。

矢印を示す方法は幾つかありますが、今回はプレイヤーの上に矢印を表示する方法について考えてみます。

方向を示す3つの方法

目的地までの移動先を示す方法ですが、ざっと考えて3つ思いつきました。

  • ゴールの方向だけを見るするパターン
  • 中間点の方向を示すパターン
  • 経路を探索して方向を取得するパターン

実際にどんな内容か考えを詰めてみます。

ゴールに至る方向だけを示すパターン

まず思いついたのが、ゴールの方向を示すパターンです。

ルートに関わらず矢印だけを示すので、実は回り道するようなケースでは逆に惑わされる事もありますが、逆に考えれば「気付き」を与える機会でもあります。

凄くシンプルな表示ですが、無いよりは遥かに良いです。

f:id:tsubaki_t1:20160803234456j:plain

実装は非常にシンプルです。とにかく、カーソルが対象を向けば良いのです。という事で、Lookatメソッドを使って強引に向けます。

gist.github.com

中間点で方向を示すパターン

ゴールに至る方向だけを示すパターンでは、回り道のような道がある場合、道に迷うかもしれません。そこで、ゴールとスタートの間に中間点を設置し、中間点の位置へ向けて矢印を示すパターンを考えてみます。

f:id:tsubaki_t1:20160803235837j:plain

中間点に近づいたら、次の中間点を示す感じで進むので、開発者敵に進む方向を提示しやすそうです。

gist.github.com

これを少し応用してるのが、StandardAssetsのUtilityに含まれるWaypointシリーズかなと思います。あっちは目標点に向けて移動ですが。

tsubakit1.hateblo.jp

経路を探索して方向を得るパターン

もう一つが、経路探索で最短経路を得るパターンです。経路探索で行うので、道順を間違えた場合でもルート再検索を行ってくれます。
但し、経路探索AIを動かすのでゲームによっては余計な負荷を生むかもしれません。また、Navmeshを設定できない所には移動出来ません。

f:id:tsubaki_t1:20160804002045j:plain

これを行うには、幾つか設定する必要があります。

まずはNavmeshをベイクします。

tsubakit1.hateblo.jp

f:id:tsubaki_t1:20160804001934j:plain

次に、NavmeshAgentを用意します。基本的にNavmeshAgent自身に動させる事は無いので、streeting系のパラメータは全部0に設定しておきます。

f:id:tsubaki_t1:20160804005120j:plain

後は経路探索で移動先を得て、向かうべき方向へ矢印を向けます。
NavmeshAgentは経路を更新してもらうために使っていいるので、移動や向きを変更する機能は使いません。よってupdateRotationupdatePositionにfalseを設定して移動しないようにします。後、NavmeshAgentの基本位置を移動するため、nextPositionに常に現在地を流し込んでいます。

後はagent.steeringTargetで次の曲がり角の座標を取得し、ソコに向けて矢印を向けるだけです。

gist.github.com

f:id:tsubaki_t1:20160804005006g:plain

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

【Unity】ライト毎に作る影の解像度を設定する

Unity 5.4からライト毎に影の解像度を設定出来るようになりました。

影の解像度設定

f:id:tsubaki_t1:20160802232213j:plain

Unity 5.4から、ライト毎に影の解像度を設定することが出来るようになりました。

GetComponent<Light> ().shadowCustomResolution = 解像度;

これで影の解像度を設定出来ます。解像度を落とす事で、影用のテクスチャを下げる事が出来ます。
少し分かりにくいのが、0~1や1~100%や解像度指定ではなく、intの数値を指定している点です。0だと最高解像度になるのですが、大体同じような値にしたい場合は3000を指定しました。

確認すると、3000~2000にかけて少し汚くなっています。
3000~300にはかなり差があり、300~200にかけては結構な違いが見て取れます。

f:id:tsubaki_t1:20160802232959j:plain

 

 シャドウマップにもソコソコの差が出ます。

f:id:tsubaki_t1:20160802234040j:plain

 

なお、シャドウマップの解像度はビデオメモリや環境に応じて自動的に減らしていくそうです(スクリーンデータとレンダリングテクスチャデータを格納するのに必要なメモリが消費されます。そして、残りのビデオメモリの 3分の1 は、シャドウマップで使用するために確保されます)。つまり、モバイル等ではどうしても汚い解像度になるかもしれません。

要するに、コレの基本的用途はライトマプの解像度を減らすことという事です。

 

f:id:tsubaki_t1:20160803001033j:plain

関連

docs.unity3d.com

baba-s.hatenablog.com

tsubakit1.hateblo.jp

【Unity】ゲームの起動後 Awakeより前にメソッドを実行する

この記事は、アプリ起動時に指定のメソッドを呼ぶ「RuntimeInitializeOnLoadMethod」に可能性を感じたが錯覚だった気が で絶望した戦士たちが、よく見たらそんなこと無かったと気づくストーリーである。

要するに書き直し。

RuntimeInitializeOnLoadMethod

RuntimeInitializeOnLoadMethodはAttribute(属性)である。彼は、ゲーム開始時に設定したメソッドを呼び出す為に存在するのだ。

例えば下のように記述した場合、ゲーム開始時にGameObjectをシーンに一つ作成してくれます。

gist.github.com

f:id:tsubaki_t1:20160728202300j:plain

さらにRuntimeInitializeOnLoadMethodの強力な所は、シーンにオブジェクトを配置しなくともメソッドが呼び出される事です。そのため、ゲーム起動時に必ず呼び出す必要のある処理は、このメソッドに定義しておくことでコンポーネントを設定せずとも呼び出すことが可能という訳です。

さらに、RuntimeInitializeOnLoadMethodはGameObjectを生成してみせたように、UnityのAPIを呼び出すことが可能です。スタティックコンストラクタやコンストラクタだとこの辺りは呼び出せないので、その辺りも嬉しい所です。

Awakeの前にRuntimeInitializeOnLoadMethodを呼び出す

RuntimeInitializeOnLoadMethodはそのままで呼ぶと、OnEnableの後に呼ばれます。つまりRuntimeInitializeOnLoadMethodが設定した何らかのパラメータにアクセス出来るようになるのは、少なくともAwakeでは無理でOnEnableまで待つ必要がある訳でした。

しかし何時の間にか付いたのか最初からついていたのか、実は引数にRuntimeInitializeLoadType.BeforeSceneLoadを設定することで、Awakeより前に呼び出す事が可能だったみたいです。

gist.github.com

f:id:tsubaki_t1:20160728204015j:plain

RuntimeInitializeLoadType.BeforeSceneLoadを設定したメソッドはAwakeより先に、1回のみ呼びだされます。

RuntimeInitializeLoadType.AfterSceneLoadを設定したメソッドは、OnEnableの後に呼び出されます。

例:ゲームに必要な処理を生成する

一つの例です。

例えばゲームの進行において必ず必要となるオブジェクト(重要OBJ)があったとします。これを他のコンポーネントが必要とする前に設定する方法は、概ね3つです。

  • 重要OBJをシーンに事前に配置しておく
  • コンポーネントが参照する際に重要OBJが無ければ生成する
  • 重要OBJがコンポーネント群を生成する、あるいはシーンをロードする

で、RuntimeInitializeOnLoadMethodをうまく活用すると4つ目

  • 重要OBJをゲーム開始時に生成する

が出来る訳です。
例えば下のような感じでオブジェクトを生成すれば、全Awakeが安定してオブジェクトを取得出来ます。(二周目は知りません)

gist.github.com

f:id:tsubaki_t1:20160728210943j:plain

ただし、コレをsingletonに使うのは少々問題かもしれません。というのも、下のような問題があるからです。

呼ばれなくても呼ばれるRuntimeInitializeOnLoadMethod

色々と便利そうではあるRuntimeInitializeOnLoadMethodですが、一つ使用するに辺り確実に注意すべき点があります。それは、定義したら場合呼びたくない状況でも呼ばれるという事です。

例えば下のようにログを非表示にするメソッドをRuntimeInitializeOnLoadMethodで定義すると、ログは表示されなくなります。

gist.github.comこの処理はプロジェクトの中にコードを置くだけで発動してしまうので、非常に追いにくい問題となります。

特に、ログといった分かりやすいパラメータなら兎も角、staticなフィールドをnullで埋めるみたいな処理を書かれ、即座にnull reference exceptionが発生しないような状況の場合、これは非常に追いにくい問題になりそうです。

呼出順の設定は出来ない

もう一つの問題は、RuntimeInitializeOnLoadMethod自体の呼出順を設定することが出来ない事です。

コンポーネントのコールバックのいくつかの呼出順はExecute Orderやオブジェクト内のコンポーネント順で設定出来ますが、RuntimeInitializeOnLoadMethodは制御出来ません。(まぁ、多分名前順かクラスID順ですが)

なので、相互的に関係するのであれば、複数定義するのではなく、単一の機能に処理を詰め込んだ方が良さそうです。

便利な機能だが使う際には注意を

Awakeより前に呼べると分かったので、割と可能性を感じるレベルになりましたが、やはり問答無用で呼ばれてしまうのが不安な所です。

記述した処理はシンボルで囲ってON/OFFを楽に設定できるようにした方が良いかもしれません。

kan-kikuchi.hatenablog.co

関連

tsubakit1.hateblo.jp