在软件打包后要想查看Unity的日志非常麻烦,所以想在游戏内直接按键呼出日志(之所以不叫控制台是因为此窗口并没有写Console.ReadLine功能)。参考StackOverflow上外国人写的脚本,更新到最新的语法并解决了2020版本以后部分语法的Obsolete问题,并新增日志筛选和窗口大小自适应功能。
效果如下:
默认按键我设置为 ~ 键,在Esc下方,致敬CSGO控制台。
功能介绍:
下方三个show Toggle分别是筛选普通、Warning和Error日志;
Collapse是将相同内容合并成一条,在你的程序输出大量无意义内容时效果很好;
Clear按钮是清除所有日志,但清除的只是UGUI上的,此路径下Unity Runtime输出的 默认日志还在:C:\Users\username\AppData\LocalLow\CompanyName\ProductName\Player.log
窗口可以直接用鼠标拖动,故没有在Inspector里写窗口位置。默认位置是距屏幕左上角20x20像素
脚本外部选项:
按键可自行更改,最大日志数量只有在勾选了 限制日志记录数量 才会生效。
建议自己封装一个Debug类
日志窗口大小默认是屏幕的一半大小,在编辑器修改这个数值后需要刷新一下才会生效。
具体代码如下:
using System.Collections.Generic;
using UnityEngine;
public class RuntimeLog : MonoBehaviour
{
[Header("打开日志的按键")]
[SerializeField] private KeyCode toggleKey = KeyCode.BackQuote; // 打开日志的按键
[Header("是否限制日志记录数量")]
[SerializeField] private bool restrictLogCount = false; // 是否限制日志记录数量
[Header("最大日志数量")]
[SerializeField] private int maxLogs = 10000; // 最大日志数量
[Header("日志显示筛选控制")]
[SerializeField] private bool showLog = true; // 控制是否显示普通日志
[SerializeField] private bool showWarning = false; // 控制是否显示警告日志
[SerializeField] private bool showError = true; // 控制是否显示错误日志
[Header("日志窗口大小")]
[SerializeField] private float windowWidth = Screen.width / 2f;
[SerializeField] private float windowHight = Screen.height / 2f;
private readonly List<Log> logs = new List<Log>();
private Vector2 scrollPosition;
private bool visible;
private bool collapse;
private static readonly Dictionary<LogType, Color> logTypeColors = new Dictionary<LogType, Color>
{
{ LogType.Assert, Color.white },
{ LogType.Error, Color.red },
{ LogType.Exception, Color.red },
{ LogType.Log, Color.white },
{ LogType.Warning, Color.yellow },
};
private const string windowTitle = "日志";
private const int margin = 20;
private static readonly GUIContent clearLabel = new GUIContent("Clear", "清除日志内容");
private static readonly GUIContent collapseLabel = new GUIContent("Collapse", "隐藏重复的日志");
private static readonly GUIContent showLogLabel = new GUIContent("showLog", "控制是否显示普通日志"); // 控制是否显示普通日志
private static readonly GUIContent showWarningLabel = new GUIContent("showWarning", "控制是否显示警告日志"); // 控制是否显示警告日志
private static readonly GUIContent showErrorLabel = new GUIContent("showError", "控制是否显示错误日志"); // 控制是否显示错误日志
private readonly Rect titleBarRect = new Rect(0, 0, 10000, 20);
private Rect windowRect = new Rect();
private void OnEnable()
{
windowRect = new Rect(margin, margin, windowWidth, windowHight);
Application.logMessageReceived += HandleLog;
}
private void OnDisable()
{
Application.logMessageReceived -= HandleLog; // 注销回调
}
private void Update()
{
if (Input.GetKeyDown(toggleKey))
{
visible = !visible;
}
}
private void OnGUI()
{
if (!visible) return;
windowRect = GUILayout.Window(1, windowRect, DrawConsoleWindow, windowTitle);
}
private void DrawConsoleWindow(int windowID)
{
DrawLogsList();
DrawToolbar();
GUI.DragWindow(titleBarRect);
}
private void DrawLogsList()
{
scrollPosition = GUILayout.BeginScrollView(scrollPosition);
for (var i = 0; i < logs.Count; i++)
{
var log = logs[i];
// 根据用户设置的显示控制来过滤日志
if ((log.type == LogType.Log && !showLog) ||
(log.type == LogType.Warning && !showWarning) ||
(log.type == LogType.Error && !showError))
{
continue; // 如果该类型的日志被禁用,则跳过
}
if (collapse && i > 0 && log.message == logs[i - 1].message)
{
continue; // 如果开启了折叠功能且日志消息与上一条相同,跳过
}
GUI.contentColor = logTypeColors[log.type];
GUILayout.Label(log.message);
}
GUILayout.EndScrollView();
GUI.contentColor = Color.white;
}
private void DrawToolbar()
{
GUILayout.BeginHorizontal();
if (GUILayout.Button(clearLabel))
{
logs.Clear(); // 清空日志
}
showLog = GUILayout.Toggle(showLog, showLogLabel, GUILayout.ExpandWidth(false));
showWarning = GUILayout.Toggle(showWarning, showWarningLabel, GUILayout.ExpandWidth(false));
showError = GUILayout.Toggle(showError, showErrorLabel, GUILayout.ExpandWidth(false));
collapse = GUILayout.Toggle(collapse, collapseLabel, GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal();
}
private void HandleLog(string message, string stackTrace, LogType type)
{
logs.Add(new Log
{
message = message,
stackTrace = stackTrace,
type = type
});
TrimExcessLogs();
}
private void TrimExcessLogs()
{
if (!restrictLogCount) return;
var excessLogs = logs.Count - maxLogs;
if (excessLogs > 0)
{
logs.RemoveRange(0, excessLogs); // 删除超过最大日志数量的日志
}
}
// 用于存储日志的结构体
private struct Log
{
public string message;
public string stackTrace;
public LogType type;
}
}
此脚本只要挂载到任意物体上即可,场景里不需要有Canvas也可以显示。