Unity中实现自定义调试器
Posted Hello Bug.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity中实现自定义调试器相关的知识,希望对你有一定的参考价值。
一:前言
在Unity编辑器下可以查看log输出、内存信息、系统信息等,但发布到移动端很多信息都无法查看,这个自定义的调试器可以查看一些游戏信息,方便调试
二:使用
——在游戏启动时调用Debugger.Ins.OpenDebugger()开启调试器
三:代码
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
}
以上是关于Unity中实现自定义调试器的主要内容,如果未能解决你的问题,请参考以下文章