Unity 实现Log实时输出到屏幕或控制台上<一>

最后更新于:2022-04-01 09:50:02

本文章由cartzhang编写,转载请注明出处。 所有权利保留。  文章链接:http://blog.csdn.net/cartzhang/article/details/49818953 作者:cartzhang ### 一、Unity 打印日志 Unity中,在其编辑器上有个专门的Console,快捷键:shift + Ctrl+ c 。 代码中的Debug.Log("this is a test");就会打印到这里。 但是在打包后,只有从Log中找到,能不能找到一个可以实时显示的工具呢? 很明显,必须有啊!!要不写这篇不就是瞎扯了么?!! 我辗转腾挪,到处寻觅,我肯定不是第一个有这个想法的人。 终于有一天,我来到了七环!!!找到了几种方法,与君共享!! ### 二、我想有个控制台 之前说的Debug.Log();此函数是打印Unity控制台的。 好办,有高人已经重新把控制台给换了地方,打印到界面的控制台上。 就是类似控制台的一个界面。 先放结果图样: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-09_56dfda85d308f.jpg) #### 1.问题来了,怎么实现的呢? 上代码: 我给改了名字叫TestConsole.cs了,因为之前名字为Console,这样想我这样都在一个工程中为大家测试,容易造成混乱。 ~~~ //#define USE_TESTCONSOLE using System.Collections.Generic; using UnityEngine; namespace Consolation { /// <summary> /// A console to display Unity's debug logs in-game. /// </summary> class TestConsole : MonoBehaviour { #if USE_TESTCONSOLE struct Log { public string message; public string stackTrace; public LogType type; } #region Inspector Settings /// <summary> /// The hotkey to show and hide the console window. /// </summary> public KeyCode toggleKey = KeyCode.BackQuote; /// <summary> /// Whether to open the window by shaking the device (mobile-only). /// </summary> public bool shakeToOpen = true; /// <summary> /// The (squared) acceleration above which the window should open. /// </summary> public float shakeAcceleration = 3f; /// <summary> /// Whether to only keep a certain number of logs. /// /// Setting this can be helpful if memory usage is a concern. /// </summary> public bool restrictLogCount = false; /// <summary> /// Number of logs to keep before removing old ones. /// </summary> public int maxLogs = 1000; #endregion readonly List<Log> logs = new List<Log>(); Vector2 scrollPosition; bool visible; bool collapse; // Visual elements: 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 }, }; const string windowTitle = "Console"; const int margin = 20; static readonly GUIContent clearLabel = new GUIContent("Clear", "Clear the contents of the console."); static readonly GUIContent collapseLabel = new GUIContent("Collapse", "Hide repeated messages."); readonly Rect titleBarRect = new Rect(0, 0, 10000, 20); Rect windowRect = new Rect(margin, margin, Screen.width - (margin * 2), Screen.height - (margin * 2)); void OnEnable() { #if UNITY_5 Application.logMessageReceived += HandleLog; #else Application.RegisterLogCallback(HandleLog); #endif } void OnDisable() { #if UNITY_5 Application.logMessageReceived -= HandleLog; #else Application.RegisterLogCallback(null); #endif } void Update() { if (Input.GetKeyDown(toggleKey)) { visible = !visible; } if (shakeToOpen && Input.acceleration.sqrMagnitude > shakeAcceleration) { visible = true; } } void OnGUI() { if (!visible) { return; } windowRect = GUILayout.Window(123456, windowRect, DrawConsoleWindow, windowTitle); } /// <summary> /// Displays a window that lists the recorded logs. /// </summary> /// <param name="windowID">Window ID.</param> void DrawConsoleWindow(int windowID) { DrawLogsList(); DrawToolbar(); // Allow the window to be dragged by its title bar. GUI.DragWindow(titleBarRect); } /// <summary> /// Displays a scrollable list of logs. /// </summary> void DrawLogsList() { scrollPosition = GUILayout.BeginScrollView(scrollPosition); // Iterate through the recorded logs. for (var i = 0; i < logs.Count; i++) { var log = logs[i]; // Combine identical messages if collapse option is chosen. if (collapse && i > 0) { var previousMessage = logs[i - 1].message; if (log.message == previousMessage) { continue; } } GUI.contentColor = logTypeColors[log.type]; GUILayout.Label(log.message); } GUILayout.EndScrollView(); // Ensure GUI colour is reset before drawing other components. GUI.contentColor = Color.white; } /// <summary> /// Displays options for filtering and changing the logs list. /// </summary> void DrawToolbar() { GUILayout.BeginHorizontal(); if (GUILayout.Button(clearLabel)) { logs.Clear(); } collapse = GUILayout.Toggle(collapse, collapseLabel, GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } /// <summary> /// Records a log from the log callback. /// </summary> /// <param name="message">Message.</param> /// <param name="stackTrace">Trace of where the message came from.</param> /// <param name="type">Type of message (error, exception, warning, assert).</param> void HandleLog(string message, string stackTrace, LogType type) { logs.Add(new Log { message = message, stackTrace = stackTrace, type = type, }); TrimExcessLogs(); } /// <summary> /// Removes old logs that exceed the maximum number allowed. /// </summary> void TrimExcessLogs() { if (!restrictLogCount) { return; } var amountToRemove = Mathf.Max(logs.Count - maxLogs, 0); if (amountToRemove == 0) { return; } logs.RemoveRange(0, amountToRemove); } #endif } } ~~~ 我在代码最前面**添加了宏定义,使用的时候屏蔽此宏定义即可**。 #### 2.怎么使用呢? 恩。我写的使用很简单。 随便写个C#代码,在Update中测试的。 ~~~ // Update is called once per frame void Update () { //DebugConsole.Log(" test s"); Debug.Log("Debug log test"); Console.WriteLine("this is Console Write line test "); /// //DebugConsole.instance.AddMessage("this is instance AddMessage test by cartzhang", "warning"); //DebugConsole.Log("this is debug console log test cartzhang"); } ~~~ #### 3.结果上面已经说明了。 这里就不重复了。 #### 4.这怎么实现的呢? 原理很简单。写一个面板,往上面写字啊! 说下啊,这个有个切换按键,就是可以控制是否显示这个面板的,按键为BackQuote,你也可以修改,BackQuote这个键呢,在ESC按键的下面就是这个“~”。 ### 三、这不是我想要的,我要显示在屏幕上。 我想要显示在控制台上,就是CMD出来的那样。 可以啊! #### 1. 直接写在屏幕上的代码 不过,我先赠送一个显示在屏幕上的。 这样我觉得大部分的人就会满足了,最起码不用自己写GUI .Label()了啊。 说明这个是国外友人好早之前写的,我只改变了其中某些不符合现在Unity 5 的语句,其他没有动。 还是代码: ~~~ /*==== DebugConsole.cs ==================================================== * Class for handling multi-line, multi-color debugging messages. * Original Author: Jeremy Hollingsworth * Based On: Version 1.2.1 Mar 02, 2006 * * Modified: Simon Waite * Date: 22 Feb 2007 * * Modification to original script to allow pixel-correct line spacing * * Setting the boolean pixelCorrect changes the units in lineSpacing property * to pixels, so you have a pixel correct gui font in your console. * * It also checks every frame if the screen is resized to make sure the * line spacing is correct (To see this; drag and let go in the editor * and the text spacing will snap back) * * USAGE: * ::Drop in your standard assets folder (if you want to change any of the * default settings in the inspector, create an empty GameObject and attach * this script to it from you standard assets folder. That will provide * access to the default settings in the inspector) * * ::To use, call DebugConsole.functionOrProperty() where * functionOrProperty = one of the following: * * -Log(string message, string color) Adds "message" to the list with the * "color" color. Color is optional and can be any of the following: "error", * "warning", or "normal". Default is normal. * * Clear() Clears all messages * * isVisible (true,false) Toggles the visibility of the output. Does _not_ * clear the messages. * * isDraggable (true, false) Toggles mouse drag functionality * =========================================================================*/ //#define USE_DEBUGCONSOLE using UnityEngine; using System.Collections; public class DebugConsole : MonoBehaviour { #if USE_DEBUGCONSOLE public GameObject DebugGui = null; // The GUI that will be duplicated public Vector3 defaultGuiPosition = new Vector3(0.01F, 0.98F, 0F); public Vector3 defaultGuiScale = new Vector3(0.5F, 0.5F, 1F); public Color normal = Color.green; public Color warning = Color.yellow; public Color error = Color.red; public int maxMessages = 30; // The max number of messages displayed public float lineSpacing = 0.02F; // The amount of space between lines public ArrayList messages = new ArrayList(); public ArrayList guis = new ArrayList(); public ArrayList colors = new ArrayList(); public bool draggable = true; // Can the output be dragged around at runtime by default? public bool visible = true; // Does output show on screen by default or do we have to enable it with code? public bool pixelCorrect = false; // set to be pixel Correct linespacing public static bool isVisible { get { return DebugConsole.instance.visible; } set { DebugConsole.instance.visible = value; if (value == true) { DebugConsole.instance.Display(); } else if (value == false) { DebugConsole.instance.ClearScreen(); } } } public static bool isDraggable { get { return DebugConsole.instance.draggable; } set { DebugConsole.instance.draggable = value; } } private static DebugConsole s_Instance = null; // Our instance to allow this script to be called without a direct connection. public static DebugConsole instance { get { if (s_Instance == null) { s_Instance = FindObjectOfType(typeof(DebugConsole)) as DebugConsole; if (s_Instance == null) { GameObject console = new GameObject(); console.AddComponent<DebugConsole>(); console.name = "DebugConsoleController"; s_Instance = FindObjectOfType(typeof(DebugConsole)) as DebugConsole; DebugConsole.instance.InitGuis(); } } return s_Instance; } } void Awake() { s_Instance = this; InitGuis(); } protected bool guisCreated = false; protected float screenHeight =-1; public void InitGuis() { float usedLineSpacing = lineSpacing; screenHeight = Screen.height; if(pixelCorrect) usedLineSpacing = 1.0F / screenHeight * usedLineSpacing; if (guisCreated == false) { if (DebugGui == null) // If an external GUIText is not set, provide the default GUIText { DebugGui = new GameObject(); DebugGui.AddComponent<GUIText>(); DebugGui.name = "DebugGUI(0)"; DebugGui.transform.position = defaultGuiPosition; DebugGui.transform.localScale = defaultGuiScale; } // Create our GUI objects to our maxMessages count Vector3 position = DebugGui.transform.position; guis.Add(DebugGui); int x = 1; while (x < maxMessages) { position.y -= usedLineSpacing; GameObject clone = null; clone = (GameObject)Instantiate(DebugGui, position, transform.rotation); clone.name = string.Format("DebugGUI({0})", x); guis.Add(clone); position = clone.transform.position; x += 1; } x = 0; while (x < guis.Count) { GameObject temp = (GameObject)guis[x]; temp.transform.parent = DebugGui.transform; x++; } guisCreated = true; } else { // we're called on a screensize change, so fiddle with sizes Vector3 position = DebugGui.transform.position; for(int x=0;x < guis.Count; x++) { position.y -= usedLineSpacing; GameObject temp = (GameObject)guis[x]; temp.transform.position= position; } } } bool connectedToMouse = false; void Update() { // If we are visible and the screenHeight has changed, reset linespacing if (visible == true && screenHeight != Screen.height) { InitGuis(); } if (draggable == true) { if (Input.GetMouseButtonDown(0)) { if (connectedToMouse == false && DebugGui.GetComponent<GUIText>().HitTest((Vector3)Input.mousePosition) == true) { connectedToMouse = true; } else if (connectedToMouse == true) { connectedToMouse = false; } } if (connectedToMouse == true) { float posX = DebugGui.transform.position.x; float posY = DebugGui.transform.position.y; posX = Input.mousePosition.x / Screen.width; posY = Input.mousePosition.y / Screen.height; DebugGui.transform.position = new Vector3(posX, posY, 0F); } } } //+++++++++ INTERFACE FUNCTIONS ++++++++++++++++++++++++++++++++ public static void Log(string message, string color) { DebugConsole.instance.AddMessage(message, color); } //++++ OVERLOAD ++++ public static void Log(string message) { DebugConsole.instance.AddMessage(message); } public static void Clear() { DebugConsole.instance.ClearMessages(); } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //---------- void AddMesage(string message, string color) ------ //Adds a mesage to the list //-------------------------------------------------------------- public void AddMessage(string message, string color) { messages.Add(message); colors.Add(color); Display(); } //++++++++++ OVERLOAD for AddMessage ++++++++++++++++++++++++++++ // Overloads AddMessage to only require one argument(message) //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public void AddMessage(string message) { messages.Add(message); colors.Add("normal"); Display(); } //----------- void ClearMessages() ------------------------------ // Clears the messages from the screen and the lists //--------------------------------------------------------------- public void ClearMessages() { messages.Clear(); colors.Clear(); ClearScreen(); } //-------- void ClearScreen() ---------------------------------- // Clears all output from all GUI objects //-------------------------------------------------------------- void ClearScreen() { if (guis.Count < maxMessages) { //do nothing as we haven't created our guis yet } else { int x = 0; while (x < guis.Count) { GameObject gui = (GameObject)guis[x]; gui.GetComponent<GUIText>().text = ""; //increment and loop x += 1; } } } //---------- void Prune() --------------------------------------- // Prunes the array to fit within the maxMessages limit //--------------------------------------------------------------- void Prune() { int diff; if (messages.Count > maxMessages) { if (messages.Count <= 0) { diff = 0; } else { diff = messages.Count - maxMessages; } messages.RemoveRange(0, (int)diff); colors.RemoveRange(0, (int)diff); } } //---------- void Display() ------------------------------------- // Displays the list and handles coloring //--------------------------------------------------------------- void Display() { //check if we are set to display if (visible == false) { ClearScreen(); } else if (visible == true) { if (messages.Count > maxMessages) { Prune(); } // Carry on with display int x = 0; if (guis.Count < maxMessages) { //do nothing as we havent created our guis yet } else { while (x < messages.Count) { GameObject gui = (GameObject)guis[x]; //set our color switch ((string)colors[x]) { case "normal": gui.GetComponent<GUIText>().material.color = normal; break; case "warning": gui.GetComponent<GUIText>().material.color = warning; break; case "error": gui.GetComponent<GUIText>().material.color = error; break; } //now set the text for this element gui.GetComponent<GUIText>().text = (string)messages[x]; //increment and loop x += 1; } } } } #endif }// End DebugConsole Class ~~~ #### 2.使用方法 ~~~ //DebugConsole.instance.AddMessage("this is instance AddMessage test by cartzhang", "warning"); //DebugConsole.Log("this is debug console log test cartzhang"); ~~~ #### 3.结果如图 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-09_56dfda8600847.jpg) ### 四、这还不是我想要的,我要显示在控制台上,就是CMD出来的那样。 好吧,你赢了!! 你往下看吧! [就是这个,你要的控制台《二》](http://blog.csdn.net/cartzhang/article/details/49884507) -----------THE END --------------- 若有问题,请随时联系! 非常感谢! -------- 由于担心篇幅过长,写成下一篇吧。 再次感谢各位!
';