UE4 除錯技巧分享 (一)

俗話說的好
給他魚吃不如教他釣魚
今天要分享幾個我平常在用的技巧

心理建設

如果你是有程式背景,但是正在用blueprint(BP)開發。
那我會建議你要先幫自己做好心裡建設。
你在用的是開發原始碼的引擎,
遇到問題時應該儘量往引擎內部追,
不要馬上就找繞過(workaround)的方法或求救。
那樣作你很快就會想放棄,因為無法進步,遇到問題無法自救。

硬體設備


雖說是技巧心得,理論上要跟硬體無關,但是這個真的要講一下。
想追code一定要準備好2個螢幕以上,至少一個螢幕是UE4 Editor,另一個是Visual Studio。
單螢幕的話光是切換視窗就亂掉了。

技巧分享

這裡面的技巧應該比較零散,所以可以跳著看。

不寫Code就直接顯示變數值在螢幕上

如果問我只能寫一條的話,我一定選這一條。
這個是我第一常用的技巧了,大部分我們想到要得知某一個值,就是跑去Actor或是Component的Tick裡面下PrintString,這樣資訊就會顯示在畫面上。如下圖。



可是有的時候bug是機率出現的,好不容易bug發生了,想看某個值是否異常,但是當下卻沒有埋PrintString,難道只能放棄了嗎?

其實沒有,引擎提供了強大的console command "DisplayAll",讓我們可以直接拿到變數值並顯示於螢幕。如圖。



DisplayAll的使用方法是:
DisplayAll [ClassName] [PropertyName]

大小寫無分別,所以可以不管大小寫。

ClassName的部份,可分為C++與BP class兩種。

如果你要追查的class是C++ class,那麼直接輸入C++的名稱就好,
但是要去除第一個字。例如

AActor應該輸入Actor

想知道movement移動速度的最大值可下
displayall charactermovementcomponent maxwalkspeed


如果你要追查的class是BP,那麼你要輸入[BP的名稱_C],

舉例來說
有一個BP名稱為BP_CodeTraceActor 裡面有一個變數是value
那麼要輸入的是
DisplayAll BP_CodeTraceActor_c value

PropertyName的部份,只要這個變數有被定義為UPROPERTY,就可以拿到值。BP所有的變數應該都有UPROPERTY,所以沒問題。

資料顯示出來後,我通常會搭配桌面錄影軟體搭配測試,一有問題就可以把影片檔抓出來單格播放,抓出異常的時間點,然後再回去想想問題可能出在哪裡。

故障排除

如果輸入之後畫面沒任何東西,建議先輸入一些一定會出現的指令確認環境
例如
diaplayall playercontroller spawnLocation
如果這樣看的到,那可能是你的class name打錯,系統找不到。
如果這樣還看不到,檢查一下自己的環境是不是Debug / Development,還是有什麼東西關掉。

如果輸入之後畫面有字,但是沒有值(有綠色的字沒有紅色的字),那可能是PropertyName打錯,建議檢查一下。

我宣布放棄DisplayAll列出來的資訊

只要執行Console Command 
DisplayClear 
就可以了

DisplayAll使用條件限制與缺點

DisplayAll只會在Debug以及Development顯示,所以如果在Test跟Shipping是看不到的。

Dedicated Server因為沒有螢幕,所以也看不到。
但是如果Dedicated Server + SingleProcess模式的話,畫面上會同時列出Server跟Client的值,很好用。

相反的Editor/ Packaged Development Game都看的到,建議可以多加利用。

使用DisplayAll最大的缺點就是只能根據class列出,沒有辦法針對某個class的某個實體(Instance)輸出。所以class沒有選擇好的話就會列出過多資訊,無法好好地做判斷。

另一個就是如果值在一個frame裡面會變動多次,想要從DisplayAll抓出問題也沒辦法,畢竟這個功能一個frame只會更新一次。

避免程式碼被Optimize造成中斷點失效

一般我們都是使用Development Editor在開發,但是因為編譯器會做Code Optimization的關係,有的時候中斷點會無效或異常。

經驗上有以下幾種現象會因為Code Optimize產生:

1. 斷點失效,雖然Visual Studio顯示該行有下斷點,但是有執行卻不停。

2. 斷點下不到準確的行數,例如下在53行卻顯示斷點在55行。

3. 執行順序怪異,跳下後又跳上,或是直接跳過整段,或是走到一半就離開函式。

4. 看不到變數值

下圖就是想看變數MutableThis內容看不到的範例。


這個時候,如果真的非得知道這個值,

常見的解法就是加Log強制印出,或是編譯DebugGame Editor,或是Debug Editor等等。

但是我個人最常用的方式是直接使用Macro Define把想看的函式夾起來,不用改DebugGame Editor或是Debug Editor。

範例如下

PRAGMA_DISABLE_OPTIMIZATION

//Your codes here

PRAGMA_ENABLE_OPTIMIZATION

下圖就是使用PRAGMA後可以成功拿到值的範例




這個方法有幾個好處:

1. 編譯速度快,因為相當於改cpp code而已,不像切換成DebugGame Editor,如果先前沒有build過要等很久。
2. 省硬碟空間,切換成DebugGame Editor,就會多出Debug版本的dll,吃掉硬碟空間。
3. 效能沒有受到犧牲,如果用DebugEditor的話,整個編輯器會變得很慢,這個方法不會。

這個方法的缺點:

目前我使用到最大的缺點就是,這段PRAGMA要記得除錯完就刪掉,不然這段程式碼都不會做Optimization,執行效能是會受到影響的。

然後有很少數的情況夾了還是有部分看不到,這時候我就會直接夾整個cpp檔,通常就沒問題了。

其實還有一個缺點,就是這兩行我永遠背不起來,每次都要去筆記本裡面複製貼上。

對我來說,這個方法沒什麼負擔跟缺點,很推薦大家學起來,推推!

下回預告
預計下個禮拜會分享第二集,是有關如何在UE4中使用中斷點的部份

留言

這個網誌中的熱門文章

UE4 GameplayAbilitySystem - GameplayEffect & GameplayCue 如何設定參數

UE4 除錯技巧分享 (二)