はじめに
デバッグ時に書いたDebug.Log
を忘れて放置してしまい、ビルド後もログを吐き続けさせてしまった経験はありませんか?
ビルド設定をOFFればビルド後のlog.txt
への吐き出しを止めることはできます。が、それでもDebug.Log
は実行されてしまうのでその分の実行コストが無駄になってしまいます。
今回は、このDebug.Log
をUnityEditor上で作業している時のみ動作させるようにしてみます。
先に結論を書くと
#if/#endifよりもConditional属性を使おう
- #id/#endifで実行のon/offはできるがメソッドの呼び出しコストは健在なので無駄が残る
- メソッドにConditional属性をつけることで、コンパイラがメソッド呼び出しそのものをスキップするようにしてくれるようになる
解説
下準備
Debug.Log
を直接呼ばず、ラップして呼び出す形にします。
public static class DebugLogger
{
public static void Log(object o)
{
UnityEngine.Debug.Log(o);
}
}
DebugLogger.Log("This is log text.");
方法1: #ifと#endifを使う
#ifと#endifを使うことで、特定の条件の時のみ対象のコードブロックをコンパイルするように指定することができます。
これを用いて、UNITY_EDITOR
のDefineが存在するときのみDebug.Log
を実行するようにします。
public static class DebugLogger
{
public static void Log(object o)
{
#if UNITY_EDITOR
UnityEngine.Debug.Log(o);
#endif
}
}
こうすることで、DebugLogger.Log
をビルド後に呼び出したとしても、Debug.Log
のブロックが実行されないためログが吐き出されることはありません。ですが、この方法ではDebugLogger.Logの呼び出しコストが残ったままになってしまい、結局Debug.Log
を直接呼び出してるのとそんなに変わりません。
ではその対策としてメソッドごと#ifブロックで包んだとしても、今度はビルド時に未定義扱いになりビルドエラーが発生してしまい上手く行きません。
public static class DebugLogger
{
#if UNITY_EDITOR
//ビルド時にこのLogメソッドが未定義扱いになり呼び出し箇所があるとビルドエラーになる
public static void Log(object o)
{
UnityEngine.Debug.Log(o);
}
#endif
}
方法2:Conditional属性を使う
別の方法として、Conditional属性を使う方法があります。
Conditional属性でメソッドをマークすることで、対象のDefineが定義されている場合のみメソッドが実行されるようにコンパイラが処理してくれるようになります。
using System.Diagnostics;
public static class DebugLogger
{
[Conditional("UNITY_EDITOR")]
public static void Log(object o)
{
UnityEngine.Debug.Log(o);
}
}
DebugLogger.Log("This is log text.");
Conditional属性を使うことで、メソッド定義は残したままにできるのでビルド時にエラーになることはありません。また、コンパイラがメソッドの呼び出しをスキップするようにビルドしてくれるため、メソッドの呼び出しコストもなくすことができます。
まとめ
メソッドの中身をまるごと#ifで包んでいた人は、Conditional属性を使う方法に書き換えることをオススメします。
#おまけ
LiveConsoleってAssetがログを色付けしてくれて見やすかったので、色付きでログ吐く拡張メソッドを生やしてみました。
using System.Diagnostics;
using Debug = UnityEngine.Debug;
namespace Hogehoge
{
public static class ForLogExtensions
{
[Conditional("UNITY_EDITOR")]
public static void Red(this object t,string tabMessage = "Red")
{
Debug.Log(string.Format("[{0}:r]{1}",tabMessage, t));
}
[Conditional("UNITY_EDITOR")]
public static void Green(this object t, string tabMessage = "Green")
{
Debug.Log(string.Format("[{0}:g]{1}", tabMessage, t));
}
[Conditional("UNITY_EDITOR")]
public static void Cyan(this object t, string tabMessage = "Cyan")
{
Debug.Log(string.Format("[{0}:c]{1}", tabMessage, t));
}
[Conditional("UNITY_EDITOR")]
public static void Yellow(this object t, string tabMessage = "Yellow")
{
Debug.Log(string.Format("[{0}:y]{1}", tabMessage, t));
}
[Conditional("UNITY_EDITOR")]
public static void Orange(this object t, string tabMessage = "Orange")
{
Debug.Log(string.Format("[{0}:o]{1}", tabMessage, t));
}
[Conditional("UNITY_EDITOR")]
public static void Magenta(this object t, string tabMessage = "Magenta")
{
Debug.Log(string.Format("[{0}:m]{1}", tabMessage, t));
}
[Conditional("UNITY_EDITOR")]
public static void Blue(this object t, string tabMessage = "Blue")
{
Debug.Log(string.Format("[{0}:b]{1}", tabMessage, t));
}
}
}
//拡張メソッドを呼ぶだけ
void Update()
{
transform.position.Red("Position");
transform.rotation.Blue("Rotation");
}