Unity 游戏框架搭建 (九) 减少加班利器-QConsole

为毛要实现这个工具?

  • 在我小时候,每当游戏在真机运行时,我们看到的日志是这样的。9.减少加班利器-QConsole  - 图1没高亮啊,还有乱七八糟的堆栈信息,好干扰日志查看,好影响心情。

  • 还有就是必须始终连着usb线啊,我想要想躺着测试。。。以上种种原因,QConsole诞生了。

如何使用?

使用方式和QLog一样,在初始化出调用,简单的一句。

  1. QConsole.Instance();

就好了,使用之后效果是这样的。9.减少加班利器-QConsole  - 图2在Editor模式下,F1控制开关。

在真机上需要在屏幕上同时按下五个手指就可以控制开关了。(本来考虑11个手指萌一下的)。

实现思路:

1.首先要想办法获取Log,这个和上一篇介绍的QLog一样,需要使用Application.logMessageReceived这个api。

2.获取到的Log信息要存在一个Queue或者List中,然后把Log输出到屏幕上就ok了。

3.输出到屏幕上使用的是OnGUI回调和 GUILayout.Window这个api, 总共三步。

贴上代码:

QConsole实现

  1. sing UnityEngine;
  2. #if UNITY_EDITOR
  3. using UnityEditor;
  4. #endif
  5. using System.Collections;
  6. using System;
  7. using System.Collections.Generic;
  8.  
  9. namespace QFramework {
  10. /// <summary>
  11. /// 控制台GUI输出类
  12. /// 包括FPS,内存使用情况,日志GUI输出
  13. /// </summary>
  14. public class QConsole : QSingleton<QConsole>
  15. {
  16.  
  17. struct ConsoleMessage
  18. {
  19. public readonly string message;
  20. public readonly string stackTrace;
  21. public readonly LogType type;
  22.  
  23. public ConsoleMessage (string message, string stackTrace, LogType type)
  24. {
  25. this.message = message;
  26. this.stackTrace = stackTrace;
  27. this.type = type;
  28. }
  29. }
  30.  
  31. /// <summary>
  32. /// Update回调
  33. /// </summary>
  34. public delegate void OnUpdateCallback();
  35. /// <summary>
  36. /// OnGUI回调
  37. /// </summary>
  38. public delegate void OnGUICallback();
  39.  
  40. public OnUpdateCallback onUpdateCallback = null;
  41. public OnGUICallback onGUICallback = null;
  42. /// <summary>
  43. /// FPS计数器
  44. /// </summary>
  45. private QFPSCounter fpsCounter = null;
  46. /// <summary>
  47. /// 内存监视器
  48. /// </summary>
  49. private QMemoryDetector memoryDetector = null;
  50. private bool showGUI = true;
  51. List<ConsoleMessage> entries = new List<ConsoleMessage>();
  52. Vector2 scrollPos;
  53. bool scrollToBottom = true;
  54. bool collapse;
  55. bool mTouching = false;
  56.  
  57. const int margin = 20;
  58. Rect windowRect = new Rect(margin + Screen.width * 0.5f, margin, Screen.width * 0.5f - (2 * margin), Screen.height - (2 * margin));
  59.  
  60. GUIContent clearLabel = new GUIContent("Clear", "Clear the contents of the console.");
  61. GUIContent collapseLabel = new GUIContent("Collapse", "Hide repeated messages.");
  62. GUIContent scrollToBottomLabel = new GUIContent("ScrollToBottom", "Scroll bar always at bottom");
  63.  
  64.  
  65. private QConsole()
  66. {
  67. this.fpsCounter = new QFPSCounter(this);
  68. this.memoryDetector = new QMemoryDetector(this);
  69. // this.showGUI = App.Instance().showLogOnGUI;
  70. QApp.Instance().onUpdate += Update;
  71. QApp.Instance().onGUI += OnGUI;
  72. Application.logMessageReceived += HandleLog;
  73.  
  74. }
  75.  
  76. ~QConsole()
  77. {
  78. Application.logMessageReceived -= HandleLog;
  79. }
  80.  
  81.  
  82. void Update()
  83. {
  84. #if UNITY_EDITOR
  85. if (Input.GetKeyUp(KeyCode.F1))
  86. this.showGUI = !this.showGUI;
  87. #elif UNITY_ANDROID
  88. if (Input.GetKeyUp(KeyCode.Escape))
  89. this.showGUI = !this.showGUI;
  90. #elif UNITY_IOS
  91. if (!mTouching && Input.touchCount == 4)
  92. {
  93. mTouching = true;
  94. this.showGUI = !this.showGUI;
  95. } else if (Input.touchCount == 0){
  96. mTouching = false;
  97. }
  98. #endif
  99.  
  100. if (this.onUpdateCallback != null)
  101. this.onUpdateCallback();
  102. }
  103.  
  104. void OnGUI()
  105. {
  106. if (!this.showGUI)
  107. return;
  108.  
  109. if (this.onGUICallback != null)
  110. this.onGUICallback ();
  111.  
  112. if (GUI.Button (new Rect (100, 100, 200, 100), "清空数据")) {
  113. PlayerPrefs.DeleteAll ();
  114. #if UNITY_EDITOR
  115. EditorApplication.isPlaying = false;
  116. #else
  117. Application.Quit();
  118. #endif
  119. }
  120. windowRect = GUILayout.Window(123456, windowRect, ConsoleWindow, "Console");
  121. }
  122.  
  123.  
  124. /// <summary>
  125. /// A window displaying the logged messages.
  126. /// </summary>
  127. void ConsoleWindow (int windowID)
  128. {
  129. if (scrollToBottom) {
  130. GUILayout.BeginScrollView (Vector2.up * entries.Count * 100.0f);
  131. }
  132. else {
  133. scrollPos = GUILayout.BeginScrollView (scrollPos);
  134. }
  135. // Go through each logged entry
  136. for (int i = 0; i < entries.Count; i++) {
  137. ConsoleMessage entry = entries[i];
  138. // If this message is the same as the last one and the collapse feature is chosen, skip it
  139. if (collapse && i > 0 && entry.message == entries[i - 1].message) {
  140. continue;
  141. }
  142. // Change the text colour according to the log type
  143. switch (entry.type) {
  144. case LogType.Error:
  145. case LogType.Exception:
  146. GUI.contentColor = Color.red;
  147. break;
  148. case LogType.Warning:
  149. GUI.contentColor = Color.yellow;
  150. break;
  151. default:
  152. GUI.contentColor = Color.white;
  153. break;
  154. }
  155. if (entry.type == LogType.Exception)
  156. {
  157. GUILayout.Label(entry.message + " || " + entry.stackTrace);
  158. } else {
  159. GUILayout.Label(entry.message);
  160. }
  161. }
  162. GUI.contentColor = Color.white;
  163. GUILayout.EndScrollView();
  164. GUILayout.BeginHorizontal();
  165. // Clear button
  166. if (GUILayout.Button(clearLabel)) {
  167. entries.Clear();
  168. }
  169. // Collapse toggle
  170. collapse = GUILayout.Toggle(collapse, collapseLabel, GUILayout.ExpandWidth(false));
  171. scrollToBottom = GUILayout.Toggle (scrollToBottom, scrollToBottomLabel, GUILayout.ExpandWidth (false));
  172. GUILayout.EndHorizontal();
  173. // Set the window to be draggable by the top title bar
  174. GUI.DragWindow(new Rect(0, 0, 10000, 20));
  175. }
  176.  
  177. void HandleLog (string message, string stackTrace, LogType type)
  178. {
  179. ConsoleMessage entry = new ConsoleMessage(message, stackTrace, type);
  180. entries.Add(entry);
  181. }
  182. }
  183. }

QFPSCounter

  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. namespace QFramework {
  5. /// <summary>
  6. /// 帧率计算器
  7. /// </summary>
  8. public class QFPSCounter
  9. {
  10. // 帧率计算频率
  11. private const float calcRate = 0.5f;
  12. // 本次计算频率下帧数
  13. private int frameCount = 0;
  14. // 频率时长
  15. private float rateDuration = 0f;
  16. // 显示帧率
  17. private int fps = 0;
  18.  
  19. public QFPSCounter(QConsole console)
  20. {
  21. console.onUpdateCallback += Update;
  22. console.onGUICallback += OnGUI;
  23. }
  24.  
  25. void Start()
  26. {
  27. this.frameCount = 0;
  28. this.rateDuration = 0f;
  29. this.fps = 0;
  30. }
  31.  
  32. void Update()
  33. {
  34. ++this.frameCount;
  35. this.rateDuration += Time.deltaTime;
  36. if (this.rateDuration > calcRate)
  37. {
  38. // 计算帧率
  39. this.fps = (int)(this.frameCount / this.rateDuration);
  40. this.frameCount = 0;
  41. this.rateDuration = 0f;
  42. }
  43. }
  44.  
  45. void OnGUI()
  46. {
  47. GUI.color = Color.black;
  48. GUI.Label(new Rect(80, 20, 120, 20),"fps:" + this.fps.ToString());
  49. }
  50. }
  51.  
  52. }

QMemoryDetector

  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4.  
  5. namespace QFramework {
  6. /// <summary>
  7. /// 内存检测器,目前只是输出Profiler信息
  8. /// </summary>
  9. public class QMemoryDetector
  10. {
  11. private readonly static string TotalAllocMemroyFormation = "Alloc Memory : {0}M";
  12. private readonly static string TotalReservedMemoryFormation = "Reserved Memory : {0}M";
  13. private readonly static string TotalUnusedReservedMemoryFormation = "Unused Reserved: {0}M";
  14. private readonly static string MonoHeapFormation = "Mono Heap : {0}M";
  15. private readonly static string MonoUsedFormation = "Mono Used : {0}M";
  16. // 字节到兆
  17. private float ByteToM = 0.000001f;
  18.  
  19. private Rect allocMemoryRect;
  20. private Rect reservedMemoryRect;
  21. private Rect unusedReservedMemoryRect;
  22. private Rect monoHeapRect;
  23. private Rect monoUsedRect;
  24.  
  25. private int x = 0;
  26. private int y = 0;
  27. private int w = 0;
  28. private int h = 0;
  29.  
  30. public QMemoryDetector(QConsole console)
  31. {
  32. this.x = 60;
  33. this.y = 60;
  34. this.w = 200;
  35. this.h = 20;
  36.  
  37. this.allocMemoryRect = new Rect(x, y, w, h);
  38. this.reservedMemoryRect = new Rect(x, y + h, w, h);
  39. this.unusedReservedMemoryRect = new Rect(x, y + 2 * h, w, h);
  40. this.monoHeapRect = new Rect(x, y + 3 * h, w, h);
  41. this.monoUsedRect = new Rect(x, y + 4 * h, w, h);
  42.  
  43. console.onGUICallback += OnGUI;
  44. }
  45.  
  46. void OnGUI()
  47. {
  48. GUI.Label(this.allocMemoryRect,
  49. string.Format(TotalAllocMemroyFormation, Profiler.GetTotalAllocatedMemory() * ByteToM));
  50. GUI.Label(this.reservedMemoryRect,
  51. string.Format(TotalReservedMemoryFormation, Profiler.GetTotalReservedMemory() * ByteToM));
  52. GUI.Label(this.unusedReservedMemoryRect,
  53. string.Format(TotalUnusedReservedMemoryFormation, Profiler.GetTotalUnusedReservedMemory() * ByteToM));
  54. GUI.Label(this.monoHeapRect,
  55. string.Format(MonoHeapFormation, Profiler.GetMonoHeapSize() * ByteToM));
  56. GUI.Label(this.monoUsedRect,
  57. string.Format(MonoUsedFormation, Profiler.GetMonoUsedSize() * ByteToM));
  58. }
  59. }
  60.  
  61. }

注意事项:

  • 和上一篇介绍的QLog一样,需要依赖上上篇文章介绍的QApp。

  • QConsole初步实现来自于开源Unity插件Unity-WWW-Wrapper中的Console.cs.在此基础上添加了ScrollToBottom选项。因为这个插件的控制台不支持滚动显示Log,需要拖拽右边的scrollBar,很不方便。

  • Unity-WWW-wrapper非常不稳定,建议大家不要使用。倒是感兴趣的同学可以研究下实现,贴上地址:https://www.assetstore.unity3d.com/en/#!/content/19116。

欢迎讨论!

相关链接:

我的框架地址:https://github.com/liangxiegame/QFramework

教程源码:https://github.com/liangxiegame/QFramework/tree/master/Assets/HowToWriteUnityGameFramework/

QFramework &游戏框架搭建QQ交流群: 623597263

转载请注明地址:凉鞋的笔记http://liangxiegame.com/

微信公众号:liangxiegame

9.减少加班利器-QConsole  - 图3

如果有帮助到您:

如果觉得本篇教程对您有帮助,不妨通过以下方式赞助笔者一下,鼓励笔者继续写出更多高质量的教程,也让更多的力量加入 QFramework 。