在Unity编辑器下能够查看log输出、内存信息、系统信息等,但发布到移动端不少信息都没法查看,这个自定义的调试器能够查看一些游戏信息,方便调试编辑器
——在游戏启动时调用Debugger.Ins.OpenDebugger()开启调试器ide
using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Profiling; /// <summary> /// 调试器 /// </summary> public class Debugger : MonoBehaviour { private static Debugger _instance; public static Debugger Ins { get { if (_instance == null) { var go = new GameObject(typeof(Debugger).ToString()); GameObject.DontDestroyOnLoad(go); _instance = go.AddComponent<Debugger>(); } return _instance; } } bool showDebugger;//是否显示调试器 int windowTypeIndex;//窗口类型下标 //窗口类型字符串 string[] debuggerTypeStr = new string[] { "Log", //Log "Memory", //内存 "Screen", //屏幕 "System", //系统 "Environment"//环境 }; GUIStyle titleStyle;//标题样式 GUIStyle logStyle_selected;//log被选择的样式 GUIStyle logStyle_info;//log样式(info) GUIStyle logStyle_warning;//log样式(warning) GUIStyle logStyle_error;//log样式(error) GUIStyle stackStyle;//堆栈样式 /// <summary> /// 打开调试器 /// </summary> public void OpenDebugger() { } public void Awake() { InitStyle(); Application.logMessageReceived += LogCallBack; } private void OnDestroy() { Application.logMessageReceived -= LogCallBack; } /// <summary> /// 初始化样式 /// </summary> void InitStyle() { titleStyle = new GUIStyle(); titleStyle.fontSize = 30; titleStyle.fontStyle = FontStyle.Bold; titleStyle.alignment = TextAnchor.MiddleCenter; titleStyle.normal.textColor = Color.cyan; logStyle_selected = new GUIStyle(); logStyle_selected.fontSize = 24; logStyle_selected.normal.textColor = Color.cyan; logStyle_info = new GUIStyle(); logStyle_info.fontSize = 24; logStyle_info.normal.textColor = Color.white; logStyle_warning = new GUIStyle(); logStyle_warning.fontSize = 24; logStyle_warning.normal.textColor = Color.yellow; logStyle_error = new GUIStyle(); logStyle_error.fontSize = 24; logStyle_error.normal.textColor = Color.red; stackStyle = new GUIStyle(); stackStyle.fontSize = 24; } private void OnGUI() { if (showDebugger) { DrawDebugger(); } else { if (GUILayout.Button("调试器", GUILayout.Width(100), GUILayout.Height(100))) { showDebugger = true; } } } /// <summary> /// 绘制调试器 /// </summary> void DrawDebugger() { GUILayout.BeginVertical("box", GUILayout.MinWidth(Screen.width)); GUILayout.Label("调试器", titleStyle); GUILayout.BeginVertical("box"); windowTypeIndex = GUILayout.Toolbar(windowTypeIndex, debuggerTypeStr, GUILayout.MinWidth(Screen.width / 10), GUILayout.MinHeight(Screen.height / 20)); if (windowTypeIndex == 0) { //绘制Log窗口 DrawLogWindow(); } else if (windowTypeIndex == 1) { //绘制内存窗口 DrawMemoryWindow(); } else if (windowTypeIndex == 2) { //绘制屏幕窗口 DrawScreenWindow(); } else if (windowTypeIndex == 3) { //绘制系统窗口 DrawSystemWindow(); } else if (windowTypeIndex == 4) { //绘制环境窗口 DrawEnviromentWindow(); } GUILayout.EndVertical(); GUILayout.Space(10); GUILayout.BeginVertical("box"); if (GUILayout.Button("Hide", GUILayout.MinWidth(Screen.width / 10), GUILayout.MinHeight(Screen.height / 20))) { showDebugger = false; } if (GUILayout.Button("Close", GUILayout.MinWidth(Screen.width / 10), GUILayout.MinHeight(Screen.height / 20))) { Destroy(gameObject); _instance = null; } GUILayout.EndVertical(); GUILayout.EndVertical(); } #region Log //Log信息 public class LogInfo { public int uid; public string condition; public string stackTrace; public LogType logType; public DateTime logTime; } List<LogInfo> logCache = new List<LogInfo>();//全部Log LogInfo curLog;//当前选择的Log Vector2 logScrollPos;//log区域滑动条位置 Vector2 stackScrollPos;//堆栈区域滑动条位置 int logCounter;//log计数器 int infoCounter;//info计数器 int warningCounter;//warning计数器 int errorCounter;//error计数器 bool showInfo = true;//显示info bool showWarning = true;//显示warning bool showError = true;//显示error const float scrollSpeed = 0.02f;//滑动条速度 void LogCallBack(string condition, string stackTrace, LogType logType) { LogInfo logInfo = new LogInfo(); logInfo.uid = ++logCounter; logInfo.condition = condition; logInfo.stackTrace = stackTrace; logInfo.logType = logType; if (logType == LogType.Error || logType == LogType.Exception || logType == LogType.Assert) { errorCounter++; } else if (logType == LogType.Warning) { warningCounter++; } else { infoCounter++; } logInfo.logTime = DateTime.Now; logCache.Add(logInfo); } /// <summary> /// 绘制Log窗口 /// </summary> void DrawLogWindow() { GUILayout.BeginHorizontal(); GUILayout.BeginVertical("box"); //顶部区域 GUILayout.BeginHorizontal("box"); showInfo = GUILayout.Toggle(showInfo, string.Format("info [{0}]", infoCounter)); showWarning = GUILayout.Toggle(showWarning, string.Format("warning [{0}]", warningCounter)); showError = GUILayout.Toggle(showError, string.Format("error [{0}]", errorCounter)); if (GUILayout.Button("Clear", GUILayout.MinWidth(Screen.width / 20), GUILayout.MinHeight(Screen.height / 40))) { curLog = null; infoCounter = 0; warningCounter = 0; errorCounter = 0; logCache.Clear(); } GUILayout.EndHorizontal(); //Log区域 GUILayout.BeginVertical("box"); logScrollPos = GUILayout.BeginScrollView(logScrollPos, GUILayout.MinWidth(Screen.width * 0.8f), GUILayout.MinHeight(Screen.height * 0.3f)); foreach (var log in logCache) { if (!IsShowLog(log.logType)) continue; string infoStr = string.Format("[{0}] {1}", log.logTime.ToString("HH:mm:ss"), log.condition); if (curLog == null) { if (GUILayout.Button(infoStr, GetStyle(log.logType))) { curLog = log; } } else { if (curLog.uid == log.uid) { if (GUILayout.Button(infoStr, logStyle_selected)) { } } else { if (GUILayout.Button(infoStr, GetStyle(log.logType))) { curLog = log; } } } } GUILayout.EndScrollView(); GUILayout.EndVertical(); GUILayout.EndVertical(); GUILayout.BeginVertical(); GUILayout.FlexibleSpace(); if (GUILayout.RepeatButton("Up", GUILayout.MinWidth(100), GUILayout.MinHeight(50))) { logScrollPos += Screen.height * scrollSpeed * Vector2.down; } GUILayout.Space(10); GUILayout.BeginHorizontal(); if (GUILayout.RepeatButton("Left", GUILayout.MinWidth(50), GUILayout.MinHeight(100))) { logScrollPos += Screen.width * scrollSpeed * Vector2.left; } if (GUILayout.RepeatButton("Right", GUILayout.MinWidth(50), GUILayout.MinHeight(100))) { logScrollPos += Screen.width * scrollSpeed * Vector2.right; } GUILayout.EndHorizontal(); GUILayout.Space(10); if (GUILayout.RepeatButton("Down", GUILayout.MinWidth(100), GUILayout.MinHeight(50))) { logScrollPos += Screen.height * scrollSpeed * Vector2.up; } GUILayout.FlexibleSpace(); GUILayout.EndVertical(); GUILayout.EndHorizontal(); //堆栈区域 if (curLog == null) return; GUILayout.BeginHorizontal(); GUILayout.BeginVertical("box"); stackScrollPos = GUILayout.BeginScrollView(stackScrollPos, GUILayout.MinWidth(Screen.width * 0.8f), GUILayout.MinHeight(Screen.height * 0.3f)); string logStr = string.Format("[{0}] {1}", curLog.logTime.ToString("HH:mm:ss"), curLog.condition); string stackStr = curLog.stackTrace; GUILayout.Label(logStr); GUILayout.Space(10); GUILayout.Label(stackStr); GUILayout.EndScrollView(); GUILayout.EndVertical(); GUILayout.BeginVertical(); GUILayout.FlexibleSpace(); if (GUILayout.RepeatButton("Up", GUILayout.MinWidth(100), GUILayout.MinHeight(50))) { stackScrollPos += Screen.height * scrollSpeed * Vector2.down; } GUILayout.Space(10); GUILayout.BeginHorizontal(); if (GUILayout.RepeatButton("Left", GUILayout.MinWidth(50), GUILayout.MinHeight(100))) { stackScrollPos += Screen.width * scrollSpeed * Vector2.left; } if (GUILayout.RepeatButton("Right", GUILayout.MinWidth(50), GUILayout.MinHeight(100))) { stackScrollPos += Screen.width * scrollSpeed * Vector2.right; } GUILayout.EndHorizontal(); GUILayout.Space(10); if (GUILayout.RepeatButton("Down", GUILayout.MinWidth(100), GUILayout.MinHeight(50))) { stackScrollPos += Screen.height * scrollSpeed * Vector2.up; } GUILayout.FlexibleSpace(); GUILayout.EndVertical(); GUILayout.EndHorizontal(); } /// <summary> /// 获得样式 /// </summary> GUIStyle GetStyle(LogType logType) { switch (logType) { case LogType.Error: case LogType.Exception: case LogType.Assert: return logStyle_error; case LogType.Warning: return logStyle_warning; case LogType.Log: return logStyle_info; default: return logStyle_info; } } /// <summary> /// 是否显示此类型的Log /// </summary> bool IsShowLog(LogType logType) { switch (logType) { case LogType.Error: case LogType.Exception: case LogType.Assert: return showError; case LogType.Warning: return showWarning; case LogType.Log: return showInfo; default: return showInfo; } } #endregion #region Memory /// <summary> /// 绘制内存窗口 /// </summary> void DrawMemoryWindow() { GUILayout.BeginVertical("Box"); GUILayout.Label("总内存:" + Profiler.GetTotalReservedMemoryLong() / 1000000 + "MB"); GUILayout.Label("已占用内存:" + Profiler.GetTotalAllocatedMemoryLong() / 1000000 + "MB"); GUILayout.Label("空闲中内存:" + Profiler.GetTotalUnusedReservedMemoryLong() / 1000000 + "MB"); GUILayout.Label("总Mono堆内存:" + Profiler.GetMonoHeapSizeLong() / 1000000 + "MB"); GUILayout.Label("已占用Mono堆内存:" + Profiler.GetMonoUsedSizeLong() / 1000000 + "MB"); GUILayout.EndVertical(); } #endregion #region Screen float FPS;//帧率 float updateFpsInterval = 1;//更新帧率的间隔 float fpsCounter;//fps计数器 float lastUpdateFpsTime;//上一次更新帧率的时间 private void Update() { fpsCounter++; if (Time.realtimeSinceStartup - lastUpdateFpsTime >= updateFpsInterval) { FPS = fpsCounter / updateFpsInterval; lastUpdateFpsTime = Time.realtimeSinceStartup; fpsCounter = 0; } } /// <summary> /// 绘制屏幕窗口 /// </summary> void DrawScreenWindow() { GUILayout.BeginVertical("Box"); GUILayout.Label(string.Format("<color={0}>FPS:{1:F1}</color>", FPS < 30 ? "#FF0000" : "#00FF00", FPS)); GUILayout.Label("DPI:" + Screen.dpi); GUILayout.Label("分辨率:" + Screen.currentResolution.ToString()); GUILayout.EndVertical(); } #endregion #region System /// <summary> /// 绘制系统窗口 /// </summary> void DrawSystemWindow() { GUILayout.BeginVertical("Box"); GUILayout.Label("操做系统:" + SystemInfo.operatingSystem); GUILayout.Label("系统内存:" + SystemInfo.systemMemorySize + "MB"); GUILayout.Label("处理器:" + SystemInfo.processorType); GUILayout.Label("处理器数量:" + SystemInfo.processorCount); GUILayout.Label("显卡:" + SystemInfo.graphicsDeviceName); GUILayout.Label("显卡类型:" + SystemInfo.graphicsDeviceType); GUILayout.Label("显存:" + SystemInfo.graphicsMemorySize + "MB"); GUILayout.Label("显卡标识:" + SystemInfo.graphicsDeviceID); GUILayout.Label("显卡供应商:" + SystemInfo.graphicsDeviceVendor); GUILayout.Label("显卡供应商标识码:" + SystemInfo.graphicsDeviceVendorID); GUILayout.Label("设备模式:" + SystemInfo.deviceModel); GUILayout.Label("设备名称:" + SystemInfo.deviceName); GUILayout.Label("设备类型:" + SystemInfo.deviceType); GUILayout.Label("设备标识:" + SystemInfo.deviceUniqueIdentifier); GUILayout.EndVertical(); } #endregion #region Environment /// <summary> /// 绘制环境窗口 /// </summary> void DrawEnviromentWindow() { GUILayout.BeginVertical("box"); GUILayout.Label("项目名称:" + Application.productName); GUILayout.Label("项目包名:" + Application.identifier); GUILayout.Label("项目版本:" + Application.version); GUILayout.Label("Unity版本:" + Application.unityVersion); GUILayout.Label("公司名称:" + Application.companyName); GUILayout.EndVertical(); } #endregion }