Post

Debug Classを最適化してみましょう。


Debug.Logとは?

Debug.LogはUnityで開発中に、初心者でもベテランでも最も頻繁に使用する機能の一つだと思います。

実行中に特定の情報をConsoleに出力し、変数の値を確認したり、特定のイベントが発生したことを確認する際に主に使用されます。

したがって、開発時に便利な情報を出力したり、Debugging時に主に利用されます。

よく使うDebugの例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using UnityEngine;

public class DebugTest : MonoBehaviour
{
    private int _playerScore = 100;
    private float _playerHealth = 75.5f;
    private string _playerName = "Player1";
    private bool _isPlayerAlive = true;

    private void Start()
    {
        // 各変数を個別に出力
        Debug.Log("Player score: " + _playerScore);
        Debug.Log("Player health: " + _playerHealth);
        Debug.Log("Player name: " + _playerName);
        Debug.Log("Is player alive: " + _isPlayerAlive);

        // 変数を一行で出力
        Debug.Log($"Player: {_playerName}, Score: {_playerScore}, Health: {_playerHealth}, Alive: {_isPlayerAlive}");

        // フォーマット指定子を使用して変数を出力
        Debug.LogFormat("Player: {0}, Score: {1}, Health: {2}, Alive: {3}", _playerName, _playerScore, _playerHealth, _isPlayerAlive);

        // その他
        Debug.Log($"{nameof(_playerName)}: {_playerName}, {nameof(_playerScore)}: {_playerScore}, {nameof(_playerHealth)}: {_playerHealth}, {nameof(_isPlayerAlive)}: {_isPlayerAlive}");
        Debug.Log($"Player: {_playerName}, Score: {_playerScore}, Health: {_playerHealth}, Alive: {_isPlayerAlive}");
    }
}

image-20240421174457665 Script実行結果


BuildされたApplicationにDebug.Logは影響を与えるか?

image-20240421174807506

Game Viewでは、Debug.LogがRenderingされないのに、BuildされたApplicationに影響があるかな?

テストしてみましょう。👨‍💻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
using UnityEngine;
using UnityEngine.UI;

public class DebugTest : MonoBehaviour
{
    public Text logText;
    private void Start()
    {
        int i = 0;
        
        // Debug.Logで、iを増減させる。
        Debug.Log(++i);
        // Debug.Logで、増減させたiをGameViewに出力する。
        logText.text = i.ToString();
    }
}

image-20240421180000396

image-20240421180050329 Buid後、実行結果

はい🙋🏻、GameViewに1が出力されました。

これはDebug.Log(++i);が、BuildされたApplicationでも動作しているということです。

ため、開発に便利たけど多量に乱発される場合、性能にも影響が発生します。

これを解決するため、本ポストではDebug Classをラッピングし、BuildされたApplicationではDebug.Logが動作しないようにし、影響を与えない方法を説明します。


条件付きコンパイル

1
2
3
4
5
6
7
#if UNITY_STANDALONE
// Logic
#endif

#if UNITY_ANDROID
// Logic
#endif

Debug Classをラッピングする前に条件付きコンパイルについて調べてみましょう。

image-20240421182637683

IDEで確認してみると、現在のBuild TargetがWindow, Mac, Linuxであるため、UNITY_ANDROID, UNITY_IOSの場合、Compile自体がされていないことが確認できます。

これを利用すると簡単にUnity Editorのみ、Debug.Logが表示されるようにラッピングすることができると思います。


System.Diagnostics.Conditional Attribute

1
2
3
4
5
6
7
8
// 条件付きコンパイル
#if UNITY_EDITOR
Debug.Log("Unity Editor");
#endif

// System.Diagnostics.Conditional
[Conditional("UNITY_EDITOR")]
private void UnityEditor() => Debug.Log("Unity Editor");

役割は、条件付きコンパイルと同じですが、Attributeの形を持っているので、関数の上に書いて関数自体を条件付きコンパイルすることができます。

Debug Classをラッピングする場合、関連関数が多いため、よりきれいにScriptを管理するためConditionalを使おうと思います。


Debug Class ラッピング

image-20240421183626785

Debug機能を使用する場合、より便利に使用するため、新しいScriptの名前をDebug.csに作成します。

1
2
3
4
5
6
7
using System.Diagnostics;

public static class Debug
{
    [Conditional("UNITY_EDITOR")]
    public static void Log(object message) => UnityEngine.Debug.Log(message);
}

上で調べたConditionalを利用してUnityEngine.Debug.Logをラッピングしました。

ラッピングしたDebug.Logを利用してもう一度テストしてみましょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
using UnityEngine;
using UnityEngine.UI;

public class DebugTest : MonoBehaviour
{
    public Text logText;
    private void Start()
    {
        int i = 0;
        
        // ラッピングした、Debug.Logで、iを増減させる。
        Debug.Log(++i);
        // ラッピングした、Debug.Logで、増減させたiをGameViewに出力する。
        logText.text = i.ToString();
    }
}

Debugを利用時、in UnityEngineではなく、ラッピングしたDebug Classを利用。 image-20240421184201546

image-20240421184810586 (左)Unity Editer実行、(右)Build後実行

テスト結果を確認してみると、Unity Editorでは1、BuildされたApplicationでは0が表示され、これは希望通りUnity Editorでは、Debug.Logが動作したが、BuildされたApplicationではDebug.Logが動作しなかったことを確認しました。

ラッピングされた、Debug Class Script

上で調べたことをもとに、開発中その時その時必要な機能を追加しながら、自分だけのDebug Classを作ってみてください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
using UnityEngine;
using System.Diagnostics;
using Object = UnityEngine.Object;

/// <summary>
/// カラーリスト
/// </summary>
public enum DColor
{
    white,
    grey,
    black,
    red,
    green,
    blue,
    yellow,
    cyan,
    brown,
    
}

/// <summary>
/// Debugラッピング
/// Unityでのみ表示する。
/// </summary>
public static class Debug
{
    /******************************************
    *                roperties                *
    ******************************************/
    #region
    public static ILogger logger => UnityEngine.Debug.unityLogger;
    public static ILogger unityLogger => UnityEngine.Debug.unityLogger;
    public static bool developerConsoleVisible
    {
        get => UnityEngine.Debug.developerConsoleVisible;
        set => UnityEngine.Debug.developerConsoleVisible = value;
    }
    public static bool isDebugBuild => UnityEngine.Debug.isDebugBuild;
    #endregion
    
    /******************************************
    *                   Log                   *
    ******************************************/
    #region
    [Conditional("UNITY_EDITOR")]
    public static void Log(object message, UnityEngine.Object context) => UnityEngine.Debug.Log(message, context);
    [Conditional("UNITY_EDITOR")]
    public static void Log(object message) => UnityEngine.Debug.Log(message);
    #endregion

    /******************************************
    *                LogFormat                *
    ******************************************/
    #region
    [Conditional("UNITY_EDITOR")]
    public static void LogFormat(string format, params object[] args) => UnityEngine.Debug.LogFormat(format, args);
    [Conditional("UNITY_EDITOR")]
    public static void LogFormat(string text, DColor color) => UnityEngine.Debug.LogFormat("<color={0}>{1}</color>",color.ToString(), text);
    [Conditional("UNITY_EDITOR")]
    public static void LogFormat(Object context, string format, params object[] args) => UnityEngine.Debug.LogFormat(context, format, args);
    #endregion
    
    /******************************************
    *                 LogError                *
    ******************************************/
    #region
    [Conditional("UNITY_EDITOR")]
    public static void LogError(object message) => UnityEngine.Debug.LogError(message);
    [Conditional("UNITY_EDITOR")]
    public static void LogErrorFormat(string format, params object[] args) => UnityEngine.Debug.LogErrorFormat(format, args);
    #endregion

    /******************************************
    *               LogWarning                *
    ******************************************/
    #region
    [Conditional("UNITY_EDITOR")]
    public static void LogWarning(object message) => UnityEngine.Debug.LogWarning(message);
    [Conditional("UNITY_EDITOR")]
    public static void LogWarning(object message, UnityEngine.Object context) => UnityEngine.Debug.LogWarning(message, context);
    [Conditional("UNITY_EDITOR")]
    public static void LogWarningFormat(string format, params object[] args) => UnityEngine.Debug.LogWarningFormat(format, args);
    #endregion

    /******************************************
    *              LogAssertion               *
    ******************************************/
    #region
    [Conditional("UNITY_EDITOR")]
    public static void LogAssertion(object message, Object context) => UnityEngine.Debug.LogAssertion(message, context);
    [Conditional("UNITY_EDITOR")]
    public static void LogAssertion(object message) => UnityEngine.Debug.LogAssertion(message);
    [Conditional("UNITY_EDITOR")]
    public static void LogAssertionFormat(Object context, string format, params object[] args) => UnityEngine.Debug.LogAssertionFormat(context, format, args);
    [Conditional("UNITY_EDITOR")]
    public static void LogAssertionFormat(string format, params object[] args) => UnityEngine.Debug.LogAssertionFormat(format, args);
    #endregion
    
    /******************************************
    *                  Assert                 *
    ******************************************/
    #region
    [Conditional("UNITY_EDITOR")]
    public static void Assert(bool condition, string message, Object context) => UnityEngine.Debug.Assert(condition, message, context);
    [Conditional("UNITY_EDITOR")]
    public static void Assert(bool condition) => UnityEngine.Debug.Assert(condition);
    [Conditional("UNITY_EDITOR")]
    public static void Assert(bool condition, object message, Object context) => UnityEngine.Debug.Assert(condition, message, context);
    [Conditional("UNITY_EDITOR")]
    public static void Assert(bool condition, string message) => UnityEngine.Debug.Assert(condition, message);
    [Conditional("UNITY_EDITOR")]
    public static void Assert(bool condition, object message) => UnityEngine.Debug.Assert(condition, message);
    [Conditional("UNITY_EDITOR")]
    public static void Assert(bool condition, Object context) => UnityEngine.Debug.Assert(condition, context);
    [Conditional("UNITY_EDITOR")]
    public static void AssertFormat(bool condition, Object context, string format, params object[] args) => UnityEngine.Debug.AssertFormat(condition, context, format, args);
    [Conditional("UNITY_EDITOR")]
    public static void AssertFormat(bool condition, string format, params object[] args) => UnityEngine.Debug.AssertFormat(condition, format, args);
    #endregion
    
    /******************************************
    *               WriteLine                 *
    ******************************************/
    #region
    [Conditional("UNITY_EDITOR")]
    public static void WriteLine(string? message, string? category) => System.Diagnostics.Debug.WriteLine(message, category);
    [Conditional("UNITY_EDITOR")]
    public static void WriteLine(string format, params object?[] args) => System.Diagnostics.Debug.WriteLine(format, args);
    [Conditional("UNITY_EDITOR")]
    public static void WriteLine(string? message) => System.Diagnostics.Debug.WriteLine(message);
    [Conditional("UNITY_EDITOR")]
    public static void WriteLine(object? value) => System.Diagnostics.Debug.WriteLine(value);
    [Conditional("UNITY_EDITOR")]
    public static void WriteLine(object? value, string? category) => System.Diagnostics.Debug.WriteLine(value, category);
    #endregion
}
このポストは著作権者の CC BY-NC 4.0 ライセンスに従います。

© HAKU. Some rights reserved.