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

轉(zhuǎn)載請(qǐng)注明地址:涼鞋的筆記

為毛要實(shí)現(xiàn)這個(gè)工具?
??1.在我小時(shí)候,每當(dāng)游戲在真機(jī)運(yùn)行時(shí),我們看到的日志是這樣的。

01.png

沒高亮啊,還有亂七八糟的堆棧信息,好干擾日志查看,好影響心情精堕。

2.還有就是必須始終連著usb線啊孵淘,我想要想躺著測試。歹篓。瘫证。
以上種種原因,QConsole誕生了揉阎。

如何使用?

使用方式和QLog一樣,在初始化出調(diào)用,簡單的一句。

QConsole.Instance();  

就好了,使用之后效果是這樣的背捌。

02.png

在Editor模式下,F1控制開關(guān)毙籽。
在真機(jī)上需要在屏幕上同時(shí)按下五個(gè)手指就可以控制開關(guān)了。(本來考慮11個(gè)手指萌一下的)毡庆。

實(shí)現(xiàn)思路:
??1.首先要想辦法獲取Log,這個(gè)和上一篇介紹的QLog一樣,需要使用Application.logMessageReceived這個(gè)api坑赡。
??2.獲取到的Log信息要存在一個(gè)Queue或者List中,然后把Log輸出到屏幕上就ok了。
??3.輸出到屏幕上使用的是OnGUI回調(diào)和 GUILayout.Window這個(gè)api, 總共三步么抗。

貼上代碼:

QConsole實(shí)現(xiàn)

sing UnityEngine;  
#if UNITY_EDITOR
using UnityEditor;  
#endif
using System.Collections;  
using System;  
using System.Collections.Generic;

namespace QFramework {  
/// <summary>
/// 控制臺(tái)GUI輸出類
/// 包括FPS毅否,內(nèi)存使用情況,日志GUI輸出
/// </summary>
public class QConsole : QSingleton<QConsole>
{

    struct ConsoleMessage
    {
        public readonly string  message;
        public readonly string  stackTrace;
        public readonly LogType type;

        public ConsoleMessage (string message, string stackTrace, LogType type)
        {
            this.message    = message;
            this.stackTrace = stackTrace;
            this.type       = type;
        }
    }

    /// <summary>
    /// Update回調(diào)
    /// </summary>
    public delegate void OnUpdateCallback();
    /// <summary>
    /// OnGUI回調(diào)
    /// </summary>
    public delegate void OnGUICallback();

    public OnUpdateCallback onUpdateCallback = null;
    public OnGUICallback onGUICallback = null;
    /// <summary>
    /// FPS計(jì)數(shù)器
    /// </summary>
    private QFPSCounter fpsCounter = null;
    /// <summary>
    /// 內(nèi)存監(jiān)視器
    /// </summary>
    private QMemoryDetector memoryDetector = null;
    private bool showGUI = true;
    List<ConsoleMessage> entries = new List<ConsoleMessage>();
    Vector2 scrollPos;
    bool scrollToBottom = true;
    bool collapse;
    bool mTouching = false;

    const int margin = 20;
    Rect windowRect = new Rect(margin + Screen.width * 0.5f, margin, Screen.width * 0.5f - (2 * margin), Screen.height - (2 * margin));

    GUIContent clearLabel    = new GUIContent("Clear",    "Clear the contents of the console.");
    GUIContent collapseLabel = new GUIContent("Collapse", "Hide repeated messages.");
    GUIContent scrollToBottomLabel = new GUIContent("ScrollToBottom", "Scroll bar always at bottom");


    private QConsole()
    {
        this.fpsCounter = new QFPSCounter(this);
        this.memoryDetector = new QMemoryDetector(this);
        //        this.showGUI = App.Instance().showLogOnGUI;
        QApp.Instance().onUpdate += Update;
        QApp.Instance().onGUI += OnGUI;
        Application.logMessageReceived += HandleLog;

    }

    ~QConsole()
    {
        Application.logMessageReceived -= HandleLog;
    }


    void Update()
    {
        #if UNITY_EDITOR
        if (Input.GetKeyUp(KeyCode.F1))
            this.showGUI = !this.showGUI;
        #elif UNITY_ANDROID
        if (Input.GetKeyUp(KeyCode.Escape))
            this.showGUI = !this.showGUI;
        #elif UNITY_IOS
        if (!mTouching && Input.touchCount == 4)
        {
            mTouching = true;
            this.showGUI = !this.showGUI;
        } else if (Input.touchCount == 0){
            mTouching = false;
        }
        #endif

        if (this.onUpdateCallback != null)
            this.onUpdateCallback();
    }

    void OnGUI()
    {
        if (!this.showGUI)
            return;

        if (this.onGUICallback != null)
            this.onGUICallback ();

        if (GUI.Button (new Rect (100, 100, 200, 100), "清空數(shù)據(jù)")) {
            PlayerPrefs.DeleteAll ();
            #if UNITY_EDITOR
            EditorApplication.isPlaying = false;
            #else
            Application.Quit();
            #endif
        }
        windowRect = GUILayout.Window(123456, windowRect, ConsoleWindow, "Console");
    }


    /// <summary>
    /// A window displaying the logged messages.
    /// </summary>
    void ConsoleWindow (int windowID)
    {
        if (scrollToBottom) {
            GUILayout.BeginScrollView (Vector2.up * entries.Count * 100.0f);
        }
        else {
            scrollPos = GUILayout.BeginScrollView (scrollPos);
        }
        // Go through each logged entry
        for (int i = 0; i < entries.Count; i++) {
            ConsoleMessage entry = entries[i];
            // If this message is the same as the last one and the collapse feature is chosen, skip it
            if (collapse && i > 0 && entry.message == entries[i - 1].message) {
                continue;
            }
            // Change the text colour according to the log type
            switch (entry.type) {
                case LogType.Error:
                case LogType.Exception:
                    GUI.contentColor = Color.red;
                    break;
                case LogType.Warning:
                    GUI.contentColor = Color.yellow;
                    break;
                default:
                    GUI.contentColor = Color.white;
                    break;
            }
            if (entry.type == LogType.Exception)
            {
                GUILayout.Label(entry.message + " || " + entry.stackTrace);
            } else {
                GUILayout.Label(entry.message);
            }
        }
        GUI.contentColor = Color.white;
        GUILayout.EndScrollView();
        GUILayout.BeginHorizontal();
        // Clear button
        if (GUILayout.Button(clearLabel)) {
            entries.Clear();
        }
        // Collapse toggle
        collapse = GUILayout.Toggle(collapse, collapseLabel, GUILayout.ExpandWidth(false));
        scrollToBottom = GUILayout.Toggle (scrollToBottom, scrollToBottomLabel, GUILayout.ExpandWidth (false));
        GUILayout.EndHorizontal();
        // Set the window to be draggable by the top title bar
        GUI.DragWindow(new Rect(0, 0, 10000, 20));
    }

    void HandleLog (string message, string stackTrace, LogType type)
    {
        ConsoleMessage entry = new ConsoleMessage(message, stackTrace, type);
        entries.Add(entry);
      }
  }
}

QFPSCounter

using UnityEngine;  
using System.Collections;

namespace QFramework {  
/// <summary>
/// 幀率計(jì)算器
/// </summary>
public class QFPSCounter
{
    // 幀率計(jì)算頻率
    private const float calcRate = 0.5f;
    // 本次計(jì)算頻率下幀數(shù)
    private int frameCount = 0;
    // 頻率時(shí)長
    private float rateDuration = 0f;
    // 顯示幀率
    private int fps = 0;

    public QFPSCounter(QConsole console)
    {
        console.onUpdateCallback += Update;
        console.onGUICallback += OnGUI;
    }

    void Start()
    {
        this.frameCount = 0;
        this.rateDuration = 0f;
        this.fps = 0;
    }

    void Update()
    {
        ++this.frameCount;
        this.rateDuration += Time.deltaTime;
        if (this.rateDuration > calcRate)
        {
            // 計(jì)算幀率
            this.fps = (int)(this.frameCount / this.rateDuration);
            this.frameCount = 0;
            this.rateDuration = 0f;
        }
    }

    void OnGUI()
    {
        GUI.color = Color.black;
        GUI.Label(new Rect(80, 20, 120, 20),"fps:" + this.fps.ToString());      
      }
  }
}

QMemoryDetector

using UnityEngine;  
using System.Collections;


namespace QFramework {  
/// <summary>
/// 內(nèi)存檢測器蝇刀,目前只是輸出Profiler信息
/// </summary>
public class QMemoryDetector 
{
    private readonly static string TotalAllocMemroyFormation = "Alloc Memory : {0}M";
    private readonly static string TotalReservedMemoryFormation = "Reserved Memory : {0}M";
    private readonly static string TotalUnusedReservedMemoryFormation = "Unused Reserved: {0}M";
    private readonly static string MonoHeapFormation = "Mono Heap : {0}M";
    private readonly static string MonoUsedFormation = "Mono Used : {0}M";
    // 字節(jié)到兆
    private float ByteToM = 0.000001f;

    private Rect allocMemoryRect;
    private Rect reservedMemoryRect;
    private Rect unusedReservedMemoryRect;
    private Rect monoHeapRect;
    private Rect monoUsedRect;

    private int x = 0;
    private int y = 0;
    private int w = 0;
    private int h = 0;

    public QMemoryDetector(QConsole console)
    {
        this.x = 60;
        this.y = 60;
        this.w = 200;
        this.h = 20;

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

        console.onGUICallback += OnGUI;
    }

    void OnGUI()
    {
        GUI.Label(this.allocMemoryRect, 
            string.Format(TotalAllocMemroyFormation, Profiler.GetTotalAllocatedMemory() * ByteToM));
        GUI.Label(this.reservedMemoryRect, 
            string.Format(TotalReservedMemoryFormation, Profiler.GetTotalReservedMemory() * ByteToM));
        GUI.Label(this.unusedReservedMemoryRect, 
            string.Format(TotalUnusedReservedMemoryFormation, Profiler.GetTotalUnusedReservedMemory() * ByteToM));
        GUI.Label(this.monoHeapRect,
            string.Format(MonoHeapFormation, Profiler.GetMonoHeapSize() * ByteToM));
        GUI.Label(this.monoUsedRect,
            string.Format(MonoUsedFormation, Profiler.GetMonoUsedSize() * ByteToM));
        }
    }
}

注意事項(xiàng):

1.和上一篇介紹的QLog一樣,需要依賴上上篇文章介紹的QApp螟加。
??2.QConsole初步實(shí)現(xiàn)來自于開源Unity插件Unity-WWW-Wrapper中的Console.cs.在此基礎(chǔ)上添加了ScrollToBottom選項(xiàng)。因?yàn)檫@個(gè)插件的控制臺(tái)不支持滾動(dòng)顯示Log,需要拖拽右邊的scrollBar,很不方便吞琐。
??3.Unity-WWW-wrapper非常不穩(wěn)定,建議大家不要使用捆探。倒是感興趣的同學(xué)可以研究下實(shí)現(xiàn),貼上地址:https://www.assetstore.unity3d.com/en/#!/content/19116

歡迎討論!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末顽分,一起剝皮案震驚了整個(gè)濱河市徐许,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌卒蘸,老刑警劉巖雌隅,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異缸沃,居然都是意外死亡恰起,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門趾牧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來检盼,“玉大人,你說我怎么就攤上這事翘单《滞鳎” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵哄芜,是天一觀的道長貌亭。 經(jīng)常有香客問我,道長认臊,這世上最難降的妖魔是什么圃庭? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上剧腻,老公的妹妹穿的比我還像新娘拘央。我一直安慰自己,他們只是感情好书在,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布灰伟。 她就那樣靜靜地躺著,像睡著了一般儒旬。 火紅的嫁衣襯著肌膚如雪袱箱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天义矛,我揣著相機(jī)與錄音发笔,去河邊找鬼。 笑死凉翻,一個(gè)胖子當(dāng)著我的面吹牛了讨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播制轰,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼前计,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了垃杖?” 一聲冷哼從身側(cè)響起男杈,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎调俘,沒想到半個(gè)月后伶棒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡彩库,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年肤无,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骇钦。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡宛渐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出眯搭,到底是詐尸還是另有隱情窥翩,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布鳞仙,位于F島的核電站寇蚊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏繁扎。R本人自食惡果不足惜幔荒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望梳玫。 院中可真熱鬧爹梁,春花似錦、人聲如沸提澎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盼忌。三九已至积糯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谦纱,已是汗流浹背看成。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跨嘉,地道東北人川慌。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像祠乃,于是被迫代替她去往敵國和親梦重。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容