我们在开发中,往往会觉得unity自带的日志系统不是那么好用,比如,不能筛选日志,不能打印在屏幕上,想生成自己的日志文件,等等等等的需求,这时候就需要自己来扩展编辑器的相关功能了。
我这里实现的需求比较简单,就是给日志加了个key,可以根据这个key来对暂时不需要显示的日志进行过滤,还有就是将我们的日志打印到屏幕上去。
打印屏幕的类参考了由 Jeremy Hollingsworth 和 Simon Waite 这2人写的一个 DebugConsole.cs 类,不过他们2个的版本实在是太早了,而且还有错误和啰嗦的地方,有兴趣的话你可以去搜来看看。外加老外真的很喜欢用while循环呀,好多能用for的地方也是while,是因为这样写字比较少吗?看来大家都是懒癌晚期患者,(:зゝ∠)
一直犯懒,终于把它给写了。。。有时间我也给它扔到 github 上去。。。
外加如果想要输出日志文件,或者其它什么功能的,你就自己加就好了,我当前的需求还是挺简单的~
效果如图:
这样用
或者这样用
一共由2个类组成,一个负责控制台打印,一个负责屏幕打印
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace GameFramework
{
/// <summary>
/// 日志管理器
/// </summary>
public class DebugMgr
{
#region 日志结构
/// <summary>
/// 日志基类
/// </summary>
protected abstract class LogDataBase
{
/// <summary>
/// key
/// </summary>
public string key;
/// <summary>
/// 日志
/// </summary>
public string log;
/// <summary>
/// 构造
/// </summary>
/// <param name="_key">key</param>
/// <param name="_log">日志</param>
public LogDataBase(string _key, string _log)
{
key = _key;
log = _log;
}
/// <summary>
/// 获取log
/// </summary>
/// <param name="format">格式</param>
/// <returns>log</returns>
protected string GetLog(string format)
{
string txt = string.Format(format, key, log);
return txt;
}
/// <summary>
/// 打印
/// </summary>
/// <param name="format">格式</param>
/// <returns>日志</returns>
public abstract string Print(string format);
}
/// <summary>
/// 日志类
/// </summary>
protected class LogData : LogDataBase
{
public LogData(string key, string message)
: base(key, message)
{ }
public override string Print(string format)
{
string logTxt = base.GetLog(format);
Debug.Log(logTxt);
return logTxt;
}
}
/// <summary>
/// 警告类
/// </summary>
protected class LogWarningData : LogDataBase
{
public LogWarningData(string key, string message)
: base(key, message)
{ }
public override string Print(string format)
{
string logTxt = base.GetLog(format);
Debug.LogWarning(logTxt);
return logTxt;
}
}
/// <summary>
/// 错误类
/// </summary>
protected class LogErrorData : LogDataBase
{
public LogErrorData(string key, string message)
: base(key, message)
{ }
public override string Print(string format)
{
string logTxt = base.GetLog(format);
Debug.LogError(logTxt);
return logTxt;
}
}
#endregion 日志结构类 ------------------------------------
/// <summary>
/// 日志格式
/// </summary>
public static string format = "{0}:{1}";
/// <summary>
/// 屏幕显示
/// </summary>
public static bool screenDisplay = false;
// 过滤key集合
private static List<string> s_filterKeyList = new List<string>();
/// <summary>
/// 清除所有key
/// </summary>
public static void ClearFilterKey()
{
s_filterKeyList.Clear();
}
/// <summary>
/// 增加key
/// </summary>
/// <param name="key">key</param>
public static void AddFilterKey(string key)
{
// 不加重复的key
if (s_filterKeyList.Contains(key))
return;
s_filterKeyList.Add(key);
}
/// <summary>
/// 移除key
/// </summary>
/// <param name="key">key</param>
public static void RemoveFilterKey(string key)
{
if (s_filterKeyList.Contains(key))
s_filterKeyList.Remove(key);
}
// 打印
private static string Print(LogDataBase ld)
{
// 日志不能为空
if (ld == null)
return "";
// 日志key是被过滤的
if (s_filterKeyList.Contains(ld.key))
return "";
// 打印日志
string logTxt = ld.Print(format);
return logTxt;
}
/// <summary>
/// 日志
/// </summary>
/// <param name="log">日志</param>
/// <param name="key">key</param>
public static void Log(string log, string key = "日志")
{
LogData ld = new LogData(key, log);
string logTxt = DebugMgr.Print(ld);
if (screenDisplay)
DebugConsole.Log(logTxt);
else
DebugConsole.Clear();
}
/// <summary>
/// 警告
/// </summary>
/// <param name="log">日志</param>
/// <param name="key">key</param>
public static void LogWarning(string log, string key = "警告")
{
LogWarningData ld = new LogWarningData(key, log);
string logTxt = DebugMgr.Print(ld);
if (screenDisplay)
DebugConsole.LogWarning(logTxt);
else
DebugConsole.Clear();
}
/// <summary>
/// 错误
/// </summary>
/// <param name="log">日志</param>
/// <param name="key">key</param>
public static void LogError(string log, string key = "错误")
{
LogErrorData ld = new LogErrorData(key, log);
string logTxt = DebugMgr.Print(ld);
if (screenDisplay)
DebugConsole.LogError(logTxt);
else
DebugConsole.Clear();
}
}
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace GameFramework
{
public class DebugConsole : MonoBehaviour
{
/// <summary>
/// 日志颜色枚举
/// </summary>
public enum LogColor
{
NORMAL, WARNING, ERROR
}
/// <summary>
/// 普通颜色
/// </summary>
public Color normalColor = Color.green;
/// <summary>
/// 警告颜色
/// </summary>
public Color warningColor = Color.yellow;
/// <summary>
/// 错误颜色
/// </summary>
public Color errorColor = Color.red;
/// <summary>
/// 第一个gui组件
/// </summary>
public GameObject debugGui = null;
/// <summary>
/// 默认gui位置
/// </summary>
public Vector3 defaultGuiPosition = new Vector3(0.01f, 0.98f, 0f);
/// <summary>
/// 显示最大日志数
/// </summary>
public int maxLogs = 30;
/// <summary>
/// 行间距
/// </summary>
public float lineSpacing = 0.03f;
/// <summary>
/// 能拖动
/// </summary>
public bool draggable = true;
/// <summary>
/// 是否显示
/// </summary>
public bool visible = true;
// 集合
private List<GUIText> m_guiList = new List<GUIText>();
private List<string> m_logList = new List<string>();
private List<LogColor> m_colorList = new List<LogColor>();
// 单例
private static DebugConsole s_instance = null;
/// <summary>
/// 获取单例
/// </summary>
/// <returns>单例</returns>
public static DebugConsole GetInstance()
{
if (s_instance == null)
{
s_instance = (DebugConsole)FindObjectOfType(typeof(DebugConsole));
if (s_instance == null)
{
GameObject console = new GameObject();
console.name = "DebugConsole";
console.AddComponent<DebugConsole>();
s_instance = (DebugConsole)FindObjectOfType(typeof(DebugConsole));
}
}
return s_instance;
}
void Awake()
{
DontDestroyOnLoad(this);
s_instance = this;
this.InitGuis();
}
private void InitGuis()
{
// 初始化第一个gui
if (debugGui == null)
{
debugGui = new GameObject();
debugGui.name = "DebugGUI(0)";
debugGui.transform.SetParent(this.transform, false);
debugGui.transform.position = defaultGuiPosition;
GUIText gt = debugGui.AddComponent<GUIText>();
m_guiList.Add(gt);
}
// 创建其它的gui
Vector3 position = debugGui.transform.position;
int guiCount = 1;
while (guiCount < maxLogs)
{
position.y -= lineSpacing;
GameObject clone = (GameObject)Instantiate(debugGui, position, transform.rotation);
clone.name = string.Format("DebugGUI({0})", guiCount);
GUIText gt = clone.GetComponent<GUIText>();
m_guiList.Add(gt);
position = clone.transform.position;
++guiCount;
}
// 设置父节点
guiCount = 0;
while (guiCount < m_guiList.Count)
{
GUIText temp = (GUIText)m_guiList[guiCount];
temp.transform.parent = debugGui.transform;
++guiCount;
}
}
// 连接到手指
private bool connectedToMouse = false;
void Update()
{
// 拖拽移动
if (draggable)
{
if (Input.GetMouseButtonDown(0))
{
if (connectedToMouse)
{
connectedToMouse = false;
}
else if (connectedToMouse == false && debugGui.GetComponent<GUIText>().HitTest((Vector3)Input.mousePosition))
{
connectedToMouse = true;
}
}
if (connectedToMouse)
{
float posX = Input.mousePosition.x / Screen.width;
float posY = Input.mousePosition.y / Screen.height;
debugGui.transform.position = new Vector3(posX, posY, 0F);
}
}
}
/// <summary>
/// 清屏
/// </summary>
private void ClearScreen()
{
// 对象还没创建全的情况下不清
if (m_guiList.Count < maxLogs)
return;
int count = 0;
while (count < m_guiList.Count)
{
GUIText gt = m_guiList[count];
gt.text = "";
++count;
}
}
/// <summary>
/// 精简多出来的消息
/// </summary>
private void Prune()
{
if (m_logList.Count <= maxLogs)
return;
int diff = m_logList.Count - maxLogs;
m_logList.RemoveRange(0, diff);
m_colorList.RemoveRange(0, diff);
}
/// <summary>
/// 显示
/// </summary>
private void Display()
{
if (visible)
{
// 先尝试是否能精简
this.Prune();
// gui不够
if (m_guiList.Count < maxLogs)
return;
// 显示
int guiCount = 0;
while (guiCount < m_guiList.Count && guiCount < m_logList.Count)
{
GUIText gt = m_guiList[guiCount];
// 文本
gt.text = m_logList[guiCount];
// 颜色
LogColor lc = m_colorList[guiCount];
switch (lc)
{
case LogColor.NORMAL:
{
gt.material.color = this.normalColor;
}
break;
case LogColor.WARNING:
{
gt.material.color = this.warningColor;
}
break;
case LogColor.ERROR:
{
gt.material.color = this.errorColor;
}
break;
}
// 循环
++guiCount;
}
}
else
{
// 清屏
this.ClearScreen();
}
}
// 加日志
private void AddLog(string log, LogColor color = LogColor.NORMAL)
{
m_logList.Add(log);
m_colorList.Add(color);
this.Display();
}
// 清日志
private void ClearLog()
{
m_logList.Clear();
m_colorList.Clear();
this.ClearScreen();
}
/// <summary>
/// 日志
/// </summary>
/// <param name="log">日志</param>
public static void Log(string log)
{
DebugConsole.GetInstance().AddLog(log, LogColor.NORMAL);
}
/// <summary>
/// 警告
/// </summary>
/// <param name="log">日志</param>
public static void LogWarning(string log)
{
DebugConsole.GetInstance().AddLog(log, LogColor.WARNING);
}
/// <summary>
/// 错误
/// </summary>
/// <param name="log">日志</param>
public static void LogError(string log)
{
DebugConsole.GetInstance().AddLog(log, LogColor.ERROR);
}
/// <summary>
/// 清除
/// </summary>
public static void Clear()
{
DebugConsole.GetInstance().ClearLog();
}
}
}
测试类:
using UnityEngine;
using System.Collections;
using GameFramework;
public class Test : MonoBehaviour
{
public bool screenDisplay = false;
// Use this for initialization
void Start()
{
DebugMgr.Log("开始了");
}
private int m_count = 0;
void OnGUI()
{
if (GUI.Button(new Rect(500, 0, 100, 100), "加log"))
{
DebugMgr.screenDisplay = screenDisplay;
string log = "count = " + m_count;
DebugMgr.Log(log);
DebugMgr.LogWarning(log);
DebugMgr.LogError(log);
++m_count;
}
}
}
友情提示一下,你可能发现了,现在你左键点一下 Console 窗口下的日志,系统会给你跳转到 DebugMgr 类里,而不是真正打日志的地方,想要解决这个问题也很简单。你就把这2个类编译封装成一个单独的c#类库项目,生成dll后,再导入项目中就可以了,这样 unity 在追踪程序的堆栈调用时,跳转的位置就会指向你真正打日志的地方了,轻松又愉快~
时间: 2024-10-11 01:40:28