借鉴了往网上两位开发者的文章,自己整理了下
http://www.gad.qq.com/lore/detail/10119
http://blog.csdn.net/cartzhang/article/details/49818953
更新
-
2017/09/11 DebugerGUI 更新自定义滑动条宽度,方便用户操作
-
2018/03/29 DebugerGUI 更新Editor面板打印信息颜色分类提示、屏幕弹出框下拉条宽度、默认选项
-
2018/04/06 Debuger类添加[Conditional("EnableLog")],使this.Log与Debuger.Log同受[Conditional("EnableLog")]编译条件控制,添加NAME自定义打印标签
主要三个类
-
Debuger
-
负责对Debug的封装,显示打印的时间和输出Log以文本的形式保存到本地
-
-
DebugerExtension
-
object的扩展类 输出方式改为this.Log("打印");
-
-
DebugerGUI
-
用OnGUI让Debug输出信息显示在屏幕上方便移动终端调试(手机调试摇一摇手机打印列表就会开启)
-
Debuger对应的dll下载
而且我一直尝试更改下图滑动的宽度,希望知道的大神给我留言,不胜感谢~
效果图
使用方法:
-
添加对应的scripting define symbols :EnableLog 如果其中有其他的用 ; 符号隔离,在发布的时候把对应的EnableLog去掉打印相关的代码就不会执行,提高运行的性能,对应的dll文件放到Plugins文件夹内,打印方式改为this.Log("需要打印的字符串");
-
然后添加DebugerGUI脚本到一个GameObject 选择对应的参数,添加命名空间namespace Custom.Log ,执行打印code,开启关闭打印只需要摇晃手机即可
-
如果在类中有定义为NAME的公有字段,打印标签会换成设置的标签值
相应代码块
DebugerGUI
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
namespace Custom.Log
{
class DebugerGUI : MonoBehaviour
{
struct Log
{
public string message;
public string stackTrace;
public LogType type;
}
#region Inspector Settings
/// <summary>
/// 显示和隐藏控制台窗口的热键。
/// </summary>
[Header("显示和隐藏控制台窗口的热键")]
public KeyCode toggleKey = KeyCode.BackQuote;
/// <summary>
/// 在打印的时候是否开启堆栈打印
/// </summary>
[Header("是否开启堆栈打印")]
public bool StackLog = false;
/// <summary>
///是否保留一定数量的日志
/// </summary>
[Header("是否保留一定数量的日志")]
public bool restrictLogCount = true;
/// <summary>
/// 是否通过摇动设备(仅移动设备)来打开窗户
/// </summary>
[Header("是否通过摇动设备(仅移动设备)来打开窗户")]
public bool shakeToOpen = true;
/// <summary>
/// 显示字体大小
/// </summary>
[Header("显示字体大小")]
public float FontSize = 30;
/// <summary>
/// 显示字体大小
/// </summary>
[Header("显示拖动条宽度")]
public float ScrollbarSize = 50;
/// <summary>
/// (平方)在上面的加速度,窗口应该打开
/// </summary>
[Header("(平方)在上面的加速度,窗口应该打开")]
public float shakeAcceleration = 100f;
/// <summary>
/// 在删除旧的日志之前保持日志的数量。
/// </summary>
[Header("在删除旧的日志之前保持日志的数量")]
public int maxLogs = 1000;
#endregion
readonly List<Log> logs = new List<Log>();
/// <summary>
/// 对应横向、纵向滑动条对应的X,Y数值
/// </summary>
public Vector2 scrollPosition;
/// <summary>
/// 可见
/// </summary>
private bool visible;
/// <summary>
/// 折叠
/// </summary>
private bool collapse;
// Visual elements:
private static readonly Dictionary<LogType, Color> logTypeColors = new Dictionary<LogType, Color>
{
{ LogType.Assert, Color.white },
{ LogType.Error, Color.red },
{ LogType.Exception, Color.magenta },
{ LogType.Log, Color.green },
{ LogType.Warning, Color.yellow },
};
#region OnGUI
private const string windowTitle = "Debug(打印日志)";
//边缘
private const int margin = 20;
private static readonly GUIContent clearLabel = new GUIContent("Clear", "清空打印信息.");
private static readonly GUIContent colseLabel = new GUIContent("Close", "关闭打印面板.");
//折叠
private static readonly GUIContent collapseLabel = new GUIContent("Collapse", "隐藏重复信息.");
private readonly Rect titleBarRect = new Rect(0, 0, 10000, 20);
private Rect windowRect = new Rect(margin, margin, Screen.width - (margin * 2), Screen.height - (margin * 2));
#endregion
void OnEnable()
{
#if UNITY_5||UNITY_2017
Application.logMessageReceived += HandleLog;
#else
Application.RegisterLogCallback(HandleLog);
#endif
}
void OnDisable()
{
#if UNITY_5||UNITY_2017
Application.logMessageReceived -= HandleLog;
#else
Application.RegisterLogCallback(null);
#endif
}
void Update()
{
Running();
}
[Conditional("EnableLog")]
public void Running()
{
if (Input.GetKeyDown(toggleKey))
{
visible = !visible;
}
if (shakeToOpen && Input.acceleration.sqrMagnitude > shakeAcceleration||Input.touchCount>=6)
{
visible = true;
}
if (Input.touchCount >= 3)
{
visible = true;
}
}
void OnGUI()
{
if (!visible)
{
return;
}
windowRect = GUILayout.Window(666, windowRect, DrawConsoleWindow, windowTitle);
}
/// <summary>
/// 显示一个列出已记录日志的窗口。
/// </summary>
/// <param name="windowID">Window ID.</param>
private void DrawConsoleWindow(int windowID)
{
DrawLogsList();
DrawToolbar();
//允许拖动window的触发范围.
GUI.DragWindow(titleBarRect);
}
/// <summary>
/// 绘制log列表
/// </summary>
private void DrawLogsList()
{
GUIStyle gs_vertica = GUI.skin.verticalScrollbar;
GUIStyle gs1_vertica = GUI.skin.verticalScrollbarThumb;
gs_vertica.fixedWidth = ScrollbarSize;
gs1_vertica.fixedWidth = ScrollbarSize;
GUIStyle gs_horizontal = GUI.skin.horizontalScrollbar;
GUIStyle gs1_horizontal = GUI.skin.horizontalScrollbarThumb;
gs_horizontal.fixedHeight = ScrollbarSize;
gs1_horizontal.fixedHeight = ScrollbarSize;
scrollPosition = GUILayout.BeginScrollView(scrollPosition, false, true);
//scrollPosition = GUILayout.BeginScrollView(scrollPosition,true,true, customGuiStyle, customGuiStyle);
for (var i = 0; i < logs.Count; i++)
{
var log = logs[i];
//如果选择折叠选项,则组合相同的消息。
if (collapse && i > 0)
{
var previousMessage = logs[i - 1].message;
if (log.message == previousMessage)
{
continue;
}
}
GUI.contentColor = logTypeColors[log.type];
GUILayout.Label(log.message);
if (StackLog)
{
GUILayout.Label(log.stackTrace);
}
}
GUI.color = Color.magenta;
GUILayout.EndScrollView();
gs_vertica.fixedWidth = 0;
gs1_vertica.fixedWidth = 0;
gs_horizontal.fixedHeight = 0;
gs1_horizontal.fixedHeight = 0;
// 在绘制其他组件之前,确保GUI颜色被重置。
GUI.contentColor = Color.white;
}
/// <summary>
/// Log日志工具栏
/// </summary>
private void DrawToolbar()
{
GUILayout.BeginHorizontal();
if (GUILayout.Button(clearLabel, GUILayout.Height(40)))
{
logs.Clear();
}
if (GUILayout.Button("Stack开关", GUILayout.Height(40)))
{
StackLog = !StackLog;
}
if (GUILayout.Button(colseLabel, GUILayout.Height(40)))
{
visible = false;
}
collapse = GUILayout.Toggle(collapse, collapseLabel, GUILayout.ExpandWidth(true), GUILayout.Height(40));// GUILayout.ExpandWidth保持长宽一致
GUILayout.EndHorizontal();
}
/// <summary>
/// Debug 对应的回调处理
/// </summary>
/// <param name="message">信息.</param>
/// <param name="stackTrace">信息的来源</param>
/// <param name="type">信息类型 (error, exception, warning, assert).</param>
private void HandleLog(string message, string stackTrace, LogType type)
{
logs.Add(new Log
{
message = "<size=" + FontSize + ">" + message + "</size>",
stackTrace = "<size=" + FontSize + ">" + stackTrace + "</size>",
type = type,
});
TrimExcessLogs();
}
/// <summary>
/// 删除超过允许的最大数量的旧日志。
/// </summary>
private void TrimExcessLogs()
{
if (!restrictLogCount)
{
return;
}
var amountToRemove = Mathf.Max(logs.Count - maxLogs, 0);
if (amountToRemove == 0)
{
return;
}
logs.RemoveRange(0, amountToRemove);
}
}
}
Debuger
using System;
using System.IO;
using UnityEngine;
using System.Reflection;
using System.Diagnostics;
namespace Custom.Log
{
/// <summary>
/// Unity 的 Debug 的封装类
/// </summary>
public class Debuger
{
/// <summary>
/// 是否输出打印
/// </summary>
public static bool EnableLog = true;
/// <summary>
/// 是否显示打印时间
/// </summary>
public static bool EnableTime = true;
/// <summary>
/// 是否储存打印到文本
/// </summary>
public static bool EnableSave = false;
/// <summary>
/// 是否显示堆栈打印信息
/// </summary>
public static bool EnableStack = false;
/// <summary>
/// 打印文本保存文件夹路径
/// </summary>
public static string LogFileDir = "";
/// <summary>
/// 打印文本名称
/// </summary>
public static string LogFileName = "";
/// <summary>
/// 打印前缀
/// </summary>
public static string Prefix = "-> ";
/// <summary>
/// 打印文本流
/// </summary>
public static StreamWriter LogFileWriter = null;
/// <summary>
/// 是否使用Unity打印
/// </summary>
public static bool UseUnityEngine = true;
private static void Internal_Log(string msg, object context = null)
{
bool useUnityEngine = Debuger.UseUnityEngine;
if (useUnityEngine)
{
UnityEngine.Debug.Log(msg, (UnityEngine.Object)context);
}
else
{
Console.WriteLine(msg);
}
}
private static void Internal_LogWarning(string msg, object context = null)
{
bool useUnityEngine = Debuger.UseUnityEngine;
if (useUnityEngine)
{
UnityEngine.Debug.LogWarning(msg, (UnityEngine.Object)context);
}
else
{
Console.WriteLine(msg);
}
}
private static void Internal_LogError(string msg, object context = null)
{
bool useUnityEngine = Debuger.UseUnityEngine;
if (useUnityEngine)
{
UnityEngine.Debug.LogError(msg, (UnityEngine.Object)context);
}
else
{
Console.WriteLine(msg);
}
}
[Conditional("EnableLog")]
public static void Log(object message)
{
message = "<color=#00ff00>" + message + "</color>";
bool flag = !Debuger.EnableLog;
if (!flag)
{
string str = Debuger.GetLogTime() + message;
UnityEngine.Debug.Log(Debuger.Prefix + str, null);
Debuger.LogToFile("[I]" + str, false);
}
}
[Conditional("EnableLog")]
public static void Log(object message, object context)
{
message = "<color=#00ff00>" + message + "</color>";
bool flag = !Debuger.EnableLog;
if (!flag)
{
string str = Debuger.GetLogTime() + message;
Debuger.Internal_Log(Debuger.Prefix + str, context);
Debuger.LogToFile("[I]" + str, false);
}
}
/// <summary>
/// Debug.Log 对应封装函数
/// </summary>
/// <param name="tag">触发函数对应的类</param>
/// <param name="message">打印信息</param>
[Conditional("EnableLog")]
public static void Log(string tag, string message)
{
tag = "<color=#800080ff>" + tag + "</color>";
message = "<color=#00ff00>" + message + "</color>";
bool flag = !Debuger.EnableLog;
if (!flag)
{
message = Debuger.GetLogTime(tag, message);
Debuger.Internal_Log(Debuger.Prefix + message, null);
Debuger.LogToFile("[I]" + message, false);
}
}
/// <summary>
/// Debug.Log 对应封装函数
/// </summary>
/// <param name="tag">触发函数对应的类</param>
/// <param name="format"></param>
/// <param name="args"></param>
[Conditional("EnableLog")]
public static void Log(string tag, string format, params object[] args)
{
tag = "<color=#800080ff>" + tag + "</color>";
string message = "<color=#00ff00>" + string.Format(format, args) + "</color>";
bool flag = !Debuger.EnableLog;
if (!flag)
{
string logText = Debuger.GetLogTime(tag, message);
Debuger.Internal_Log(Debuger.Prefix + logText, null);
Debuger.LogToFile("[I]" + logText, false);
}
}
/// <summary>
/// Debug.LogWarning 对应封装函数
/// </summary>
/// <param name="message">打印信息</param>
[Conditional("EnableLog")]
public static void LogWarning(object message)
{
message = "<color=#ffff00ff>" + message + "</color>";
string str = Debuger.GetLogTime() + message;
Debuger.Internal_LogWarning(Debuger.Prefix + str, null);
Debuger.LogToFile("[W]" + str, false);
}
/// <summary>
/// Debug.LogWarning 对应封装函数
/// </summary>
/// <param name="message"></param>
/// <param name="context"></param>
[Conditional("EnableLog")]
public static void LogWarning(object message, object context)
{
message = "<color=#ffff00ff>" + message + "</color>";
string str = Debuger.GetLogTime() + message;
Debuger.Internal_LogWarning(Debuger.Prefix + str, context);
Debuger.LogToFile("[W]" + str, false);
}
/// <summary>
/// Debug.LogWarning 对应封装函数
/// </summary>
/// <param name="tag">触发函数对应的类</param>
/// <param name="message">打印信息</param>
[Conditional("EnableLog")]
public static void LogWarning(string tag, string message)
{
tag = "<color=#800080ff>" + tag + "</color>";
message = "<color=#ffff00ff>" + message + "</color>";
message = Debuger.GetLogTime(tag, message);
Debuger.Internal_LogWarning(Debuger.Prefix + message, null);
Debuger.LogToFile("[W]" + message, false);
}
/// <summary>
/// Debug.LogWarning 对应封装函数
/// </summary>
/// <param name="tag">触发函数对应的类</param>
/// <param name="format"></param>
/// <param name="args"></param>
[Conditional("EnableLog")]
public static void LogWarning(string tag, string format, params object[] args)
{
tag += "<color=#800080ff>" + tag + "</color>";
string message = "<color=#ffff00ff>" + string.Format(format, args) + "</color>";
string logText = Debuger.GetLogTime(tag, string.Format(format, args));
Debuger.Internal_LogWarning(Debuger.Prefix + logText, null);
Debuger.LogToFile("[W]" + logText, false);
}
/// <summary>
/// Debug.LogError 对应封装函数
/// </summary>
/// <param name="message">打印信息</param>
[Conditional("EnableLog")]
public static void LogError(object message)
{
message = "<color=#ff0000ff>" + message + "</color>";
string str = Debuger.GetLogTime() + message;
Debuger.Internal_LogError(Debuger.Prefix + str, null);
Debuger.LogToFile("[E]" + str, true);
}
/// <summary>
/// Debug.LogError 对应封装函数
/// </summary>
/// <param name="message">打印信息</param>
/// <param name="context"></param>
[Conditional("EnableLog")]
public static void LogError(object message, object context)
{
message = "<color=#ff0000ff>" + message + "</color>";
string str = Debuger.GetLogTime() + message;
Debuger.Internal_LogError(Debuger.Prefix + str, context);
Debuger.LogToFile("[E]" + str, true);
}
/// <summary>
/// Debug.LogError 对应封装函数
/// </summary>
/// <param name="tag">触发函数对应的类</param>
/// <param name="message">打印信息</param>
[Conditional("EnableLog")]
public static void LogError(string tag, string message)
{
tag = "<color=#800080ff>" + tag + "</color>";
message = "<color=#ff0000ff>" + message + "</color>";
message = Debuger.GetLogTime(tag, message);
Debuger.Internal_LogError(Debuger.Prefix + message, null);
Debuger.LogToFile("[E]" + message, true);
}
/// <summary>
/// Debug.LogError 对应封装函数
/// </summary>
/// <param name="tag">触发函数对应的类</param>
/// <param name="format"></param>
/// <param name="args"></param>
[Conditional("EnableLog")]
public static void LogError(string tag, string format, params object[] args)
{
tag += "<color=#800080ff>" + tag + "</color>";
string message = "<color=#ff0000ff>" + string.Format(format, args) + "</color>";
string logText = Debuger.GetLogTime(tag, string.Format(format, args));
Debuger.Internal_LogError(Debuger.Prefix + logText, null);
Debuger.LogToFile("[E]" + logText, true);
}
/// <summary>
/// 获取打印时间
/// </summary>
/// <param name="tag">触发打印信息对应的类或者NAME字段名称</param>
/// <param name="message"></param>
/// <returns></returns>
private static string GetLogTime(string tag, string message)
{
string result = "";
bool enableTime = Debuger.EnableTime;
if (enableTime)
{
result = DateTime.Now.ToString("HH:mm:ss.fff") + " ";
}
return result + tag + "::" + message;
}
/// <summary>
/// 获取打印时间
/// </summary>
/// <returns></returns>
private static string GetLogTime()
{
string result = "";
bool enableTime = Debuger.EnableTime;
if (enableTime)
{
result = DateTime.Now.ToString("HH:mm:ss.fff") + " ";
}
return result;
}
/// <summary>
/// 序列化打印信息
/// </summary>
/// <param name="message">打印信息</param>
/// <param name="EnableStack">是否开启堆栈打印</param>
private static void LogToFile(string message, bool EnableStack = false)
{
bool flag = !Debuger.EnableSave;
if (!flag)
{
bool flag2 = Debuger.LogFileWriter == null;
if (flag2)
{
Debuger.LogFileName = DateTime.Now.GetDateTimeFormats('s')[0].ToString();
Debuger.LogFileName = Debuger.LogFileName.Replace("-", "_");
Debuger.LogFileName = Debuger.LogFileName.Replace(":", "_");
Debuger.LogFileName = Debuger.LogFileName.Replace(" ", "");
Debuger.LogFileName += ".log";
bool flag3 = string.IsNullOrEmpty(Debuger.LogFileDir);
if (flag3)
{
try
{
bool useUnityEngine = Debuger.UseUnityEngine;
if (useUnityEngine)
{
Debuger.LogFileDir = Application.persistentDataPath + "/DebugerLog/";
}
else
{
string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
Debuger.LogFileDir = baseDirectory + "/DebugerLog/";
}
}
catch (Exception ex)
{
Debuger.Internal_LogError(Debuger.Prefix + "获取 Application.persistentDataPath 报错!" + ex.Message, null);
return;
}
}
string path = Debuger.LogFileDir + Debuger.LogFileName;
try
{
bool flag4 = !Directory.Exists(Debuger.LogFileDir);
if (flag4)
{
Directory.CreateDirectory(Debuger.LogFileDir);
}
Debuger.LogFileWriter = File.AppendText(path);
Debuger.LogFileWriter.AutoFlush = true;
}
catch (Exception ex2)
{
Debuger.LogFileWriter = null;
Debuger.Internal_LogError("LogToCache() " + ex2.Message + ex2.StackTrace, null);
return;
}
}
bool flag5 = Debuger.LogFileWriter != null;
if (flag5)
{
try
{
Debuger.LogFileWriter.WriteLine(message);
bool flag6 = (EnableStack || Debuger.EnableStack) && Debuger.UseUnityEngine;
if (flag6)
{
Debuger.LogFileWriter.WriteLine(StackTraceUtility.ExtractStackTrace());
}
}
catch (Exception)
{
}
}
}
}
}
}
DebugerExtension
using System;
using System.Diagnostics;
using System.Reflection;
namespace Custom.Log
{
/// <summary>
/// 自定义Debuger类的扩展类
/// </summary>
public static class DebugerExtension
{
/// <summary>
/// Debug.Log扩展,用法与Debug.Log相符
/// </summary>
/// <param name="obj">触发函数对应的类</param>
/// <param name="message">打印信息</param>
[Conditional("EnableLog")]
public static void Log(this object obj, string message)
{
bool flag = !Debuger.EnableLog;
if (!flag)
{
Debuger.Log(DebugerExtension.GetLogTag(obj), message);
}
}
/// <summary>
/// Debug.Log扩展,用法与Debug.Log相符
/// </summary>
/// <param name="obj">触发函数对应的类</param>
/// <param name="format"></param>
/// <param name="args"></param>
[Conditional("EnableLog")]
public static void Log(this object obj, string format, params object[] args)
{
bool flag = !Debuger.EnableLog;
if (!flag)
{
string message = string.Format(format, args);
Debuger.Log(DebugerExtension.GetLogTag(obj), message);
}
}
/// <summary>
/// Debug.LogWarning扩展,用法与Debug.LogWarning相符
/// </summary>
/// <param name="obj">触发函数对应的类</param>
/// <param name="message">打印信息</param>
[Conditional("EnableLog")]
public static void LogWarning(this object obj, string message)
{
Debuger.LogWarning(DebugerExtension.GetLogTag(obj), message);
}
/// <summary>
/// Debug.LogWarning扩展,用法与Debug.LogWarning相符
/// </summary>
/// <param name="obj">触发函数对应的类</param>
/// <param name="format"></param>
/// <param name="args"></param>
[Conditional("EnableLog")]
public static void LogWarning(this object obj, string format, params object[] args)
{
string message = string.Format(format, args);
Debuger.LogWarning(DebugerExtension.GetLogTag(obj), message);
}
/// <summary>
/// Debug.LogError扩展,用法与Debug.LogError相符
/// </summary>
/// <param name="obj">触发函数对应的类</param>
/// <param name="message">打印信息</param>
[Conditional("EnableLog")]
public static void LogError(this object obj, string message)
{
Debuger.LogError(DebugerExtension.GetLogTag(obj), message);
}
/// <summary>
/// Debug.LogError扩展,用法与Debug.LogError相符
/// </summary>
/// <param name="obj">触发函数对应的类</param>
/// <param name="format"></param>
/// <param name="args"></param>
[Conditional("EnableLog")]
public static void LogError(this object obj, string format, params object[] args)
{
string message = string.Format(format, args);
Debuger.LogError(DebugerExtension.GetLogTag(obj), message);
}
/// <summary>
/// 获取调用打印的类名称或者标记有NAME的字段
/// 有NAME字段的,触发类名称用NAME字段对应的赋值
/// 没有用类的名称代替
/// </summary>
/// <param name="obj">触发Log对应的类</param>
/// <returns></returns>
private static string GetLogTag(object obj)
{
FieldInfo field = obj.GetType().GetField("NAME");
bool flag = field != null;
string result;
if (flag)
{
result = (string)field.GetValue(obj);
}
else
{
result = obj.GetType().Name;
}
return result;
}
}
}