[程式] 關於UE4中的C++與Script支援的一些雜談

作者: dorgonman (dorgonman)   2017-03-06 23:17:53
blog版:http://dorgon.horizon-studio.net/archives/773
歡迎大家指教 : )
================本文開始=============
我們知道,除了使用Blueprint之外,還可以選擇使用C++來進行開發。然而,UE4中的C++有著許多跟標準C++不太一樣的規則。這是由於引擎為了減少使用C++編程時的門檻,因此在底層實作了一套Reflection(UProperty)跟Garbage Collection(GC)的機制。只要照著UE4的編程規則進行C++類別的設計,不僅可以減少各種資源管理上的議題,還能夠自動享受到由引擎方所提供的許多便利功能。
或許有人會有疑問:C#或JAVA也有Reflection跟GC,為什麼UE4還要自己用C++實作一套?直接跟Unity一樣用C#當成Script來撰寫遊戲邏輯部份不就好了嗎?
其實UE4++跟.NET C#在機制上有著根本上的不同。前者是在執行編譯之前,會先使用Unreal Header Tool(UHT)產生相關需要的資訊,然後用著同一套C++ Compiler將這些產生出來的Code編譯成可以執行的Native Code;而C#則是先編譯成Bytecode,在.NET中稱為Common Intermediate Language(CIL),然後再實際安裝到目標機器或第一次呼叫相關方法時,呼叫Just-In-Tim(JIT) Compiler將Bytecode編譯成Native Code執行。
UE4的方法可以想見,其執行速度會比較快,但由於最後的執行檔內包含了所有的Reflection資訊,因此檔案會變大;而使用Bytecode的方法,我們所損失的就只有第一次執行程式時的速度,以及一些可以使用在C++中的優化技巧。
其實在UE4釋出之前的幾代引擎,是有自己的一套UnrealScript來當成遊戲邏輯的編程使用,其第一代遊戲引擎更是在1998年就已經釋出。因此我們的問題應該要換成:為什麼要將UnrealScript從四代的移除?雖然使用Script會需要以執行期的效能為代價,但先編成Bytecode的方式,不僅可以避免因為C++語言的複雜性而造成新手進入的障礙,而且還能讓開發者減少許多等待C++編譯的時間。若真的非常需要效能應用,還是有技術能將這些Script轉譯成C++後再編譯。
相較之下,似乎沒有特別的理由堅持使用C++來進行開發,不是嗎?
是的,這也是為何官方將三代中的Kismet這套視覺編程系統進行強化,重新命名為Blueprint後,強勢回歸到四代引擎的原因。對於完全不懂程式的使用者,其實可以完全使用這套系統建構出一個遊戲。
這套強化過後的視覺化Script系統就是官方所給出的解答。
只是完全使用Blueprint來寫程式還是有不少的限制,尤其視覺編程系統實在是不適合用來撰寫複雜的邏輯。而且在多人協作上,由於寫出的檔案為Binary的格式,目前也沒辦法使用git進行merge。
基於以上限制,我們還是需要一個完整的純文字格式的Script語言給進階使用者不是嗎?不管是直譯式語言或是編譯式語言,將C++的複雜性從開發流程中隔離出來,對開發不是會比較有效率嗎?
事實上,在引擎底層是有開放接口,讓使用者自己綁定其他想使用的Script語言。而且目前在markplace上也可以找到Unreal.js這套免費的Plugin將V8 JavaScript Engine跟引擎進行綁定。其他如python、lua、C#……等等,也都有非官方的實現。
但問題是,為什麼官方堅持不在引擎層提供一套正式的純文字格式Script語言支持?根據官方於論壇上的回答,主要是因為以下幾點原因:
1. 在引擎過去幾十年來的演進中,隨著使用人數的增加,有越來越多的使用者要求將C++中的某個特性開放給Script使用。而不斷開放這些進階功能的後果,這層為了減少複雜性而封裝起來的Sandbox環境看起來就跟C++中的宣告沒二樣。這時候再透過一層Script介面層的封裝,反而增加了整體理解的複雜度。
2. 隨著Script介面層的擴張,其在跟C++層溝通的成本跟複雜度會變的非常大。又尤其要將一些比較複雜的資料型態互相傳輸時,例如Container,在Script跟C++的語意跟語法都不太相同的情況下,肯定會造成不少的維護成本。
3. 當開發者在尋求一些更進階的功能時,勢必要將程式的邏輯分割成「Script部份」跟「C++部份」,而開發時間就在雙方的呼叫邏輯撰寫地獄中損失掉了。
4. 當開發者需要進行斷點做程式的追蹤時,馬上就會發現script的debug工具跟C++使用的debug工具是完全的二回事。若你沒辦法直接從script層追到C++層的話,那麼在做除錯時就會變的非常的困難。(反之亦然)
從上面所列出的原因中我們可以發現,不支援Script有很大的原因,都是由於C++跟Script之間的互相操作性(Interoperability)在引擎演化到最後完全失控了。回歸純粹的C++架構,不僅可以解決引擎維護與除錯上的痛點,而且附加好處,則是效能上的增進與簡化跟第三方C++ Library的整合。
這個決策或許有些人並不認同,但至少我們可以看出官方目前對內建其他script上的態度。
作者: coolrobin (泳圈)   2017-03-06 23:28:00
好文推,目前也在用ue開發,希望前輩有空的話能多分享一些心得 :)
作者: windkey (揪嚕嚕)   2017-03-07 00:27:00
很棒的理解!
作者: damody (天亮damody)   2017-03-07 00:46:00
123
作者: flor18 (Folr)   2017-03-07 08:16:00
推/
作者: Frostx (Naga)   2017-03-07 09:47:00
UE4新手推
作者: riveranb (River)   2017-03-09 12:25:00
推!
作者: nickchu35 (尼克邱)   2017-03-11 19:21:00
謝謝分享~~
作者: Sidney0503 (Sidney0503)   2017-03-12 19:39:00
UE的C++不是真的C++ 就跟unity的C#不是真C#一樣XD
作者: dorgonman (dorgonman)   2017-03-12 23:30:00
確實有不一樣的規則,但真的把UHT自動產的東西攤開來還是確確實實的C++
作者: FireWolfGO   2017-04-04 03:24:00
Blueprint目前在compare跟merge的部分還是很困難不然其實Blueprint還蠻方便的 現階段我只推薦作最後的component組合跟UMG的部分用BP來做 系統建議還是用C++會比較方便 尤其是很多人同時開發的時候更是這樣

Links booklink

Contact Us: admin [ a t ] ucptt.com