Debug.Log()
をスクリプト上に仕込んでおけば、デバック作業が楽になりますよね。
Debug.Log()
で吐き出されるログは、UnityEditor上ではConsoleウィンドウから見れますし、iOSならXcode経由で、Androidならlogcatで、と見る方法はいろいろあります。
ただ僕はゲーム画面でもログが見たい!
今作っているPhotonを使ったマルチプレイのゲームなんかは、各実機のゲーム画面にログが表示されないとデバッグがしにくいのです。
というわけで、今回はゲーム画面にログを出して見たいと思います。
この記事にはUnity5.6.0f3を使用しています。
- Application.logMessageReceivedを使ってログをキャッチ!
- スクロールビューをつけることでログが多い日も安心!
- もっとログをカラフルに!
- ことのついでにスタックトレースも使っちゃおう!
- 出来上がり!
さて、どうやってログをゲーム画面に表示させましょうか。
uGUIのText
を使えば、ゲーム画面上に文字列を出すことは出来ます。
ではDebug.Log()
で出力する文字列をどのように取得すればいいのでしょうか。
スクリプト上でDebug.Log()
を呼んでいる前後で、Debug.Log()
で渡している文字列と同じものをuGUIのText
に渡してあげればいいのですが、それはさすがに面倒くさいです。
さて、Unity側に何か便利な関数やらはないものでしょうか。
Application.logMessageReceivedを使ってログをキャッチ!
Application.logMessageReceived
というイベントハンドラーがありました。
このイベントにコールバック関数を登録しておけば、ログを出力した際に呼び出されるという優れものです。
Application.logMessageReceived
に指定できるコールバックの関数は、引数3個で返り値なし。
渡される引数は以下の通りです。
第1引数:string型 ログの文字
第2引数:string型 スタックトレース
第3引数:LogType型 ログのタイプ
さっそく使ってみましょう。
LogMenu.cs
using UnityEngine; using UnityEngine.UI; public class LogMenu : MonoBehaviour { [SerializeField] private Text m_textUI = null; private void Awake() { Application.logMessageReceived += OnLogMessage; } private void OnDestroy() { Application.logMessageReceived += OnLogMessage; } private void OnLogMessage( string i_logText, string i_stackTrace, LogType i_type ) { if( string.IsNullOrEmpty( i_logText ) ) { return; } m_textUI.text += i_logText; } } // class LogMenu
以下のテストコンポーネントを使って、ログが画面に映るかテストしてみます。
using UnityEngine; using System.Collections; public class TestComponent : MonoBehaviour { private IEnumerator Start() { while( true ) { Debug.LogFormat( "Time:{0}", System.DateTime.Now ); yield return new WaitForSeconds( 1.0f ); } } } // class TestComponent
ログがゲーム画面に表示されました。
ただ……、改行し忘れてますね。
ログがごしゃごしゃになってしまっている。
uGUIのText
に文字列を渡す際に、改行コードも一緒に渡してあげましょう。
LogMenu.cs
private void OnLogMessage( string i_logText, string i_stackTrace, LogType i_type ) { if( string.IsNullOrEmpty( i_logText ) ) { return; } m_textUI.text += i_logText + System.Environment.NewLine; }
スクロールビューをつけることでログが多い日も安心!
さて、ログが出たのはいいんですが、このままじゃすぐにログが画面から溢れてしまいます。
これはuGUI側で解決しましょうか。
たしかスクロールビューという便利なものがあったような気がしますよ。
UIメニューからScrollViewを選択して作成しましょう。
そして、ContentのGameObject
に先ほど使っていたText
のUIとContentSizeFitter
を加えてっと。
3分クッキング感覚で、スクロールが出来ました。
もっとログをカラフルに!
ログにもいろいろなタイプがあります。
Debug.LogWarning()
が呼ばれていれば、何かしら不味いことが起きているんでしょうし、
Debug.LogError()
が呼ばれた日には、非常事態な状況に違いないわけです。
それらが通常のログと同じ感じに表示されていたんでは、重要なログを見逃してしまいます。
というわけで、ログに色を付けてみましょう。
Application.logMessageReceived
に登録したコールバックの引数にLogType
が渡されているはずです。
このLogType
で色分けしていきましょう。
docs.unity3d.com
LogMenu.cs
private void OnLogMessage( string i_logText, string i_stackTrace, LogType i_type ) { if( string.IsNullOrEmpty( i_logText ) ) { return; } switch( i_type ) { case LogType.Error: case LogType.Assert: case LogType.Exception: i_logText = string.Format( "<color=red>{0}</color>", i_logText ); break; case LogType.Warning: i_logText = string.Format( "<color=yellow>{0}</color>", i_logText ); break; default: break; } m_textUI.text += i_logText + System.Environment.NewLine; }
TestComponent.cs
private IEnumerator Start() { while( true ) { switch( Random.Range( 0, 3 ) ) { case 0: Debug.LogFormat( "Time:{0}", System.DateTime.Now ); break; case 1: Debug.LogWarningFormat( "Time:{0}", System.DateTime.Now ); break; case 2: Debug.LogErrorFormat( "Time:{0}", System.DateTime.Now ); break; default: break; } yield return new WaitForSeconds( 0.5f ); } }
カラフル!
いいですねー、赤い文字が事態の深刻さをあおってくれます。
ことのついでにスタックトレースも使っちゃおう!
大体望んでいた感じに作れたのですが、折角引数としてスタックトレースの文字列も渡されているのでこれも使ってみましょう。
毎回スタックトレースまで表示していたらログが溢れかえるので、Assertなど非常事態なときだけスタックトレースを表示するようにしましょう。
private void OnLogMessage( string i_logText, string i_stackTrace, LogType i_type ) { if( string.IsNullOrEmpty( i_logText ) ) { return; } if( !string.IsNullOrEmpty( i_stackTrace ) ) { switch( i_type ) { case LogType.Error: case LogType.Assert: case LogType.Exception: i_logText += System.Environment.NewLine + i_stackTrace; break; default: break; } } switch( i_type ) { case LogType.Error: case LogType.Assert: case LogType.Exception: i_logText = string.Format( "<color=red>{0}</color>", i_logText ); break; case LogType.Warning: i_logText = string.Format( "<color=yellow>{0}</color>", i_logText ); break; default: break; } m_textUI.text += i_logText + System.Environment.NewLine; }
エラーが発生した際はスタックトレースで、どのようにしてエラーが発生したのかがわかるので、よりデバッグがしやすくなりましたね。
出来上がり!
このデバッグログ出力をデバッグメニューなどに仕込めば、どんなときでもログが確認できますね。
更に改良を加えれば、ログタイプごとで表示するメニューをかえたり、文字列を検索することも出来るようになるかもしれません。
しかし、スクリプトを見返してみると、最後のスタックトレースの件はswitch
文が連続していて美しくない……。
あとで直そうっと。