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. namespace QFramework {

  9. ///
  10. /// 控制台GUI输出类
  11. /// 包括FPS,内存使用情况,日志GUI输出
  12. ///
  13. public class QConsole : QSingleton
  14. {

  15. struct ConsoleMessage

  16. {
  17. public readonly string message;
  18. public readonly string stackTrace;
  19. public readonly LogType type;

  20. public ConsoleMessage (string message, string stackTrace, LogType type)

  21. {
  22. this.message = message;
  23. this.stackTrace = stackTrace;
  24. this.type = type;
  25. }
  26. }

  27. ///

  28. /// Update回调
  29. ///
  30. public delegate void OnUpdateCallback();
  31. ///
  32. /// OnGUI回调
  33. ///
  34. public delegate void OnGUICallback();

  35. public OnUpdateCallback onUpdateCallback = null;

  36. public OnGUICallback onGUICallback = null;
  37. ///
  38. /// FPS计数器
  39. ///
  40. private QFPSCounter fpsCounter = null;
  41. ///
  42. /// 内存监视器
  43. ///
  44. private QMemoryDetector memoryDetector = null;
  45. private bool showGUI = true;
  46. List entries = new List();
  47. Vector2 scrollPos;
  48. bool scrollToBottom = true;
  49. bool collapse;
  50. bool mTouching = false;

  51. const int margin = 20;

  52. Rect windowRect = new Rect(margin + Screen. * 0.5f, margin, Screen. * 0.5f - (2 * margin), Screen. - (2 * margin));

  53. GUIContent clearLabel = new GUIContent(“Clear”, “Clear the contents of the console.”);

  54. GUIContent collapseLabel = new GUIContent(“Collapse”, “Hide repeated messages.”);
  55. GUIContent scrollToBottomLabel = new GUIContent(“ScrollToBottom”, “Scroll bar always at bottom”);

  56. private QConsole()

  57. {
  58. this.fpsCounter = new QFPSCounter(this);
  59. this.memoryDetector = new QMemoryDetector(this);
  60. // this.showGUI = App.Instance().showLogOnGUI;
  61. QApp.Instance().onUpdate += Update;
  62. QApp.Instance().onGUI += OnGUI;
  63. Application.logMessageReceived += HandleLog;

  64. }

  65. ~QConsole()

  66. {
  67. Application.logMessageReceived -= HandleLog;
  68. }

  69. void Update()

  70. {
  71. if UNITY_EDITOR

  72. if (Input.GetKeyUp(KeyCode.F1))
  73. this.showGUI = !this.showGUI;
  74. elif UNITY_ANDROID

  75. if (Input.GetKeyUp(KeyCode.Escape))
  76. this.showGUI = !this.showGUI;
  77. elif UNITY_IOS

  78. if (!mTouching && Input.touchCount == 4)
  79. {
  80. mTouching = true;
  81. this.showGUI = !this.showGUI;
  82. } else if (Input.touchCount == 0){
  83. mTouching = false;
  84. }
  85. endif

  86. if (this.onUpdateCallback != null)

  87. this.onUpdateCallback();
  88. }

  89. void OnGUI()

  90. {
  91. if (!this.showGUI)
  92. return;

  93. if (this.onGUICallback != null)

  94. this.onGUICallback ();

  95. if (GUI.Button (new Rect (100, 100, 200, 100), “清空数据”)) {

  96. PlayerPrefs.DeleteAll ();
  97. if UNITY_EDITOR

  98. EditorApplication.isPlaying = false;
  99. else

  100. Application.Quit();
  101. endif

  102. }
  103. windowRect = GUILayout.Window(123456, windowRect, ConsoleWindow, “Console”);
  104. }

  105. ///

  106. /// A window displaying the logged messages.
  107. ///
  108. void ConsoleWindow (int windowID)
  109. {
  110. if (scrollToBottom) {
  111. GUILayout.BeginScrollView (Vector2.up * entries.Count * 100.0f);
  112. }
  113. else {
  114. scrollPos = GUILayout.BeginScrollView (scrollPos);
  115. }
  116. // Go through each logged entry
  117. for (int i = 0; i < entries.Count; i++) {
  118. ConsoleMessage entry = entries[i];
  119. // If this message is the same as the last one and the collapse feature is chosen, skip it
  120. if (collapse && i > 0 && entry.message == entries[i - 1].message) {
  121. continue;
  122. }
  123. // Change the text colour according to the log type
  124. switch (entry.type) {
  125. case LogType.Error:
  126. case LogType.Exception:
  127. GUI.contentColor = Color.red;
  128. break;
  129. case LogType.Warning:
  130. GUI.contentColor = Color.yellow;
  131. break;
  132. default:
  133. GUI.contentColor = Color.white;
  134. break;
  135. }
  136. if (entry.type == LogType.Exception)
  137. {
  138. GUILayout.Label(entry.message + “ || “ + entry.stackTrace);
  139. } else {
  140. GUILayout.Label(entry.message);
  141. }
  142. }
  143. GUI.contentColor = Color.white;
  144. GUILayout.EndScrollView();
  145. GUILayout.BeginHorizontal();
  146. // Clear button
  147. if (GUILayout.Button(clearLabel)) {
  148. entries.Clear();
  149. }
  150. // Collapse toggle
  151. collapse = GUILayout.Toggle(collapse, collapseLabel, GUILayout.ExpandWidth(false));
  152. scrollToBottom = GUILayout.Toggle (scrollToBottom, scrollToBottomLabel, GUILayout.ExpandWidth (false));
  153. GUILayout.EndHorizontal();
  154. // Set the window to be draggable by the top title bar
  155. GUI.DragWindow(new Rect(0, 0, 10000, 20));
  156. }

  157. void HandleLog (string message, string stackTrace, LogType type)

  158. {
  159. ConsoleMessage entry = new ConsoleMessage(message, stackTrace, type);
  160. entries.Add(entry);
  161. }
  162. }
  163. }

QFPSCounter

  1. using UnityEngine;
  2. using System.Collections;

  3. namespace QFramework {

  4. ///
  5. /// 帧率计算器
  6. ///
  7. public class QFPSCounter
  8. {
  9. // 帧率计算频率
  10. private const float calcRate = 0.5f;
  11. // 本次计算频率下帧数
  12. private int frameCount = 0;
  13. // 频率时长
  14. private float rateDuration = 0f;
  15. // 显示帧率
  16. private int fps = 0;

  17. public QFPSCounter(QConsole console)

  18. {
  19. console.onUpdateCallback += Update;
  20. console.onGUICallback += OnGUI;
  21. }

  22. void Start()

  23. {
  24. this.frameCount = 0;
  25. this.rateDuration = 0f;
  26. this.fps = 0;
  27. }

  28. void Update()

  29. {
  30. ++this.frameCount;
  31. this.rateDuration += Time.deltaTime;
  32. if (this.rateDuration > calcRate)
  33. {
  34. // 计算帧率
  35. this.fps = (int)(this.frameCount / this.rateDuration);
  36. this.frameCount = 0;
  37. this.rateDuration = 0f;
  38. }
  39. }

  40. void OnGUI()

  41. {
  42. GUI.color = Color.black;
  43. GUI.Label(new Rect(80, 20, 120, 20),”fps:” + this.fps.ToString());
  44. }
  45. }

  46. }

QMemoryDetector

  1. using UnityEngine;
  2. using System.Collections;

  3. namespace QFramework {

  4. ///
  5. /// 内存检测器,目前只是输出Profiler信息
  6. ///
  7. public class QMemoryDetector
  8. {
  9. private readonly static string TotalAllocMemroyFormation = “Alloc Memory : {0}M”;
  10. private readonly static string TotalReservedMemoryFormation = “Reserved Memory : {0}M”;
  11. private readonly static string TotalUnusedReservedMemoryFormation = “Unused Reserved: {0}M”;
  12. private readonly static string MonoHeapFormation = “Mono Heap : {0}M”;
  13. private readonly static string MonoUsedFormation = “Mono Used : {0}M”;
  14. // 字节到兆
  15. private float ByteToM = 0.000001f;

  16. private Rect allocMemoryRect;

  17. private Rect reservedMemoryRect;
  18. private Rect unusedReservedMemoryRect;
  19. private Rect monoHeapRect;
  20. private Rect monoUsedRect;

  21. private int x = 0;

  22. private int y = 0;
  23. private int w = 0;
  24. private int h = 0;

  25. public QMemoryDetector(QConsole console)

  26. {
  27. this.x = 60;
  28. this.y = 60;
  29. this.w = 200;
  30. this.h = 20;

  31. this.allocMemoryRect = new Rect(x, y, w, h);

  32. this.reservedMemoryRect = new Rect(x, y + h, w, h);
  33. this.unusedReservedMemoryRect = new Rect(x, y + 2 * h, w, h);
  34. this.monoHeapRect = new Rect(x, y + 3 * h, w, h);
  35. this.monoUsedRect = new Rect(x, y + 4 * h, w, h);

  36. console.onGUICallback += OnGUI;

  37. }

  38. void OnGUI()

  39. {
  40. GUI.Label(this.allocMemoryRect,
  41. string.Format(TotalAllocMemroyFormation, Profiler.GetTotalAllocatedMemory() * ByteToM));
  42. GUI.Label(this.reservedMemoryRect,
  43. string.Format(TotalReservedMemoryFormation, Profiler.GetTotalReservedMemory() * ByteToM));
  44. GUI.Label(this.unusedReservedMemoryRect,
  45. string.Format(TotalUnusedReservedMemoryFormation, Profiler.GetTotalUnusedReservedMemory() * ByteToM));
  46. GUI.Label(this.monoHeapRect,
  47. string.Format(MonoHeapFormation, Profiler.GetMonoHeapSize() * ByteToM));
  48. GUI.Label(this.monoUsedRect,
  49. string.Format(MonoUsedFormation, Profiler.GetMonoUsedSize() * ByteToM));
  50. }
  51. }

  52. }

注意事项:

  • 和上一篇介绍的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 。