UE4 AddOnScreenDebugMessage實(shí)現(xiàn)原理詳解

今日被小伙伴問起這個(gè)函數(shù)


解決問題之后搜了搜網(wǎng)上的資料,發(fā)現(xiàn)解釋的都太含糊了。如下:

然而虛幻能做的并不止這么簡單,并且這個(gè)解釋也包含歧義(如何理解“相同的信息”)。于是仔細(xì)研究了一下這個(gè)函數(shù),與大家分享一下。
老規(guī)矩,先說結(jié)論,再上代碼:
虛幻用了兩個(gè)容器來存儲(chǔ)屏幕上的debug信息:

PriorityScreenMessages 是一個(gè) Trray,由虛幻自己管理生命周期,不向外提供查詢接口。
ScreenMessages 是一個(gè) TMap,開發(fā)者可追蹤到自己的debug信息,并且有配套的刪除,修改等接口。
那么傳入的這個(gè)參數(shù) Key ,實(shí)際就是每條信息的身份標(biāo)識。-1 表示沒有標(biāo)識,這些消息一次性交付,交付后脫離開發(fā)者控制。 而其他的 key,則每一個(gè) key 標(biāo)識一條消息,這也回答了開篇的問題(如何理解“相同的信息”),這個(gè)key 不僅僅是 0 這么簡單,可以傳其他的數(shù)來標(biāo)識其他的信息。
所以不上源碼的解析都是在刷流氓!下面上源碼!


上述代碼中的 if 分支非常清晰,
如果是 -1, 則不經(jīng)過查詢,用的是 PriorityScreenMessages ,根據(jù) bNewerOnTop 決定插到頭部還是尾部。
如果是其他數(shù),則先查詢 ScreenMessages ,有則改現(xiàn)有Message, 無則創(chuàng)建。
額外兩點(diǎn)說明:
1. 這里虛幻有一個(gè)非常巧妙的操作。

我們看到當(dāng)需要把Message顯示在頂端的時(shí)候(確切地說是要把Message 插到 PriorityScreenMessages 尾部),虛幻沒有直接用Insert,而是在PriorityScreenMessages尾部構(gòu)建Message 對象,節(jié)省了一次內(nèi)存開辟。

2. 我們同時(shí)注意到,對 ScreenMessages ,虛幻并沒有判斷 bNewerOnTop ,這是為什么呢?因?yàn)門Map 是一個(gè)無序的容器,雖然TMap支持排序,但是這里虛幻并未對其排序(也沒有必要),故有自己 Key 的 Messages在屏幕上的顯示順序是不固定。
那么虛幻又是如何管理這兩個(gè)容器的呢?答案在UEngine::DrawOnscreenDebugMessages中。

由于代碼太長,這里我折疊了PriorityScreenMessages ,處理邏輯是一樣的。
紅色框便是生命周期管理邏輯,虛幻用了一個(gè) TFrameValue 類型的變量 HasUpdatedScreenMessages 來標(biāo)記每一幀是否已經(jīng)計(jì)算過時(shí)間了。TFrameValue的特性是當(dāng)前幀設(shè)置過的值會(huì)在下一幀自動(dòng)失效。以確保同一幀打印多次debug,時(shí)間也只會(huì)被計(jì)算一次。
黃色框是計(jì)算屏幕位置邏輯,這里不展開講。
藍(lán)色框這里回應(yīng)一下前文,我們看到虛幻并未對 ScreenMessages 做排序,故bNewerOnTop在此沒有意義。
以上全為阿婆豬個(gè)人研究代碼的結(jié)論,如有錯(cuò)誤,歡迎大佬批評指正。

文(zhuang)藝(bi)范(fan)的結(jié)束語還沒想好,小伙伴們有想法的話,可以評論區(qū)對個(gè)線。